summaryrefslogtreecommitdiff
path: root/mojo/public/tools/bindings
diff options
context:
space:
mode:
Diffstat (limited to 'mojo/public/tools/bindings')
-rw-r--r--mojo/public/tools/bindings/BUILD.gn11
-rw-r--r--mojo/public/tools/bindings/README.md81
-rw-r--r--mojo/public/tools/bindings/blink_bindings_configuration.gni17
-rw-r--r--mojo/public/tools/bindings/chromium_bindings_configuration.gni70
-rw-r--r--mojo/public/tools/bindings/gen_data_files_list.py48
-rwxr-xr-xmojo/public/tools/bindings/generate_type_mappings.py22
-rw-r--r--mojo/public/tools/bindings/generators/__init__.py0
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl22
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl26
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl421
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl168
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl4
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl2
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl2
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl2
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl20
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module-shared-message-ids.h.tmpl35
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl1
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl20
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl9
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl55
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl4
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl31
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl4
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl80
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl32
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_unserialized_message_context.tmpl33
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl39
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl2
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl69
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_traits_definition.tmpl28
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl19
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl54
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl2
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl4
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl39
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl69
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_template_definition.tmpl4
-rw-r--r--mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl177
-rw-r--r--mojo/public/tools/bindings/generators/java_templates/header.java.tmpl3
-rw-r--r--mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl7
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/externs/interface_definition.tmpl34
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/externs/module.externs.tmpl37
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/externs/struct_definition.tmpl8
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl125
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl130
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl54
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl9
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl57
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl66
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl30
-rw-r--r--mojo/public/tools/bindings/generators/mojom_cpp_generator.py1120
-rw-r--r--mojo/public/tools/bindings/generators/mojom_java_generator.py150
-rw-r--r--mojo/public/tools/bindings/generators/mojom_js_generator.py783
-rw-r--r--mojo/public/tools/bindings/mojom.gni777
-rwxr-xr-xmojo/public/tools/bindings/mojom_bindings_generator.py353
-rw-r--r--mojo/public/tools/bindings/mojom_bindings_generator_unittest.py30
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/generator.py217
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/generator_unittest.py24
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/module.py352
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/pack.py3
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py23
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/translate.py180
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/parse/ast.py74
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/parse/conditional_features.py80
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/parse/parser.py27
-rw-r--r--mojo/public/tools/bindings/pylib/mojom_tests/generate/generator_unittest.py12
-rw-r--r--mojo/public/tools/bindings/pylib/mojom_tests/parse/conditional_features_unittest.py232
-rw-r--r--mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py5
-rw-r--r--mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py66
70 files changed, 4553 insertions, 2241 deletions
diff --git a/mojo/public/tools/bindings/BUILD.gn b/mojo/public/tools/bindings/BUILD.gn
index 153d110332..4979617303 100644
--- a/mojo/public/tools/bindings/BUILD.gn
+++ b/mojo/public/tools/bindings/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//mojo/public/tools/bindings/mojom.gni")
+import("//third_party/jinja2/jinja2.gni")
action("precompile_templates") {
sources = mojom_generator_sources
@@ -17,6 +18,7 @@ action("precompile_templates") {
"$mojom_generator_root/generators/cpp_templates/interface_response_validator_declaration.tmpl",
"$mojom_generator_root/generators/cpp_templates/interface_stub_declaration.tmpl",
"$mojom_generator_root/generators/cpp_templates/module-shared-internal.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-shared-message-ids.h.tmpl",
"$mojom_generator_root/generators/cpp_templates/module-shared.cc.tmpl",
"$mojom_generator_root/generators/cpp_templates/module-shared.h.tmpl",
"$mojom_generator_root/generators/cpp_templates/module.cc.tmpl",
@@ -29,6 +31,7 @@ action("precompile_templates") {
"$mojom_generator_root/generators/cpp_templates/struct_serialization_declaration.tmpl",
"$mojom_generator_root/generators/cpp_templates/struct_traits_declaration.tmpl",
"$mojom_generator_root/generators/cpp_templates/struct_traits_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_unserialized_message_context.tmpl",
"$mojom_generator_root/generators/cpp_templates/union_data_view_declaration.tmpl",
"$mojom_generator_root/generators/cpp_templates/union_data_view_definition.tmpl",
"$mojom_generator_root/generators/cpp_templates/union_declaration.tmpl",
@@ -55,6 +58,10 @@ action("precompile_templates") {
"$mojom_generator_root/generators/java_templates/struct.java.tmpl",
"$mojom_generator_root/generators/java_templates/union.java.tmpl",
"$mojom_generator_root/generators/js_templates/enum_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/externs/interface_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/externs/module.externs.tmpl",
+ "$mojom_generator_root/generators/js_templates/externs/struct_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/fuzzing.tmpl",
"$mojom_generator_root/generators/js_templates/interface_definition.tmpl",
"$mojom_generator_root/generators/js_templates/module.amd.tmpl",
"$mojom_generator_root/generators/js_templates/module_definition.tmpl",
@@ -63,6 +70,8 @@ action("precompile_templates") {
"$mojom_generator_root/generators/js_templates/validation_macros.tmpl",
]
script = mojom_generator_script
+
+ inputs = jinja2_sources
outputs = [
"$target_gen_dir/cpp_templates.zip",
"$target_gen_dir/java_templates.zip",
@@ -72,6 +81,6 @@ action("precompile_templates") {
"--use_bundled_pylibs",
"precompile",
"-o",
- rebase_path(target_gen_dir),
+ rebase_path(target_gen_dir, root_build_dir),
]
}
diff --git a/mojo/public/tools/bindings/README.md b/mojo/public/tools/bindings/README.md
index 737c7e61df..d1ffc448e9 100644
--- a/mojo/public/tools/bindings/README.md
+++ b/mojo/public/tools/bindings/README.md
@@ -1,12 +1,13 @@
-# ![Mojo Graphic](https://goo.gl/6CdlbH) Mojom IDL and Bindings Generator
-This document is a subset of the [Mojo documentation](/mojo).
+# Mojom IDL and Bindings Generator
+This document is a subset of the [Mojo documentation](/mojo/README.md).
[TOC]
## Overview
Mojom is the IDL for Mojo bindings interfaces. Given a `.mojom` file, the
-[bindings generator](https://cs.chromium.org/chromium/src/mojo/public/tools/bindings)
+[bindings
+generator](https://cs.chromium.org/chromium/src/mojo/public/tools/bindings/)
outputs bindings for all supported languages: **C++**, **JavaScript**, and
**Java**.
@@ -248,7 +249,7 @@ struct AllTheThings {
SampleInterface&? nullable_sample_interface_request;
associated SampleInterface associated_interface_client;
associated SampleInterface& associated_interface_request;
- assocaited SampleInterface&? maybe_another_associated_request;
+ associated SampleInterface&? maybe_another_associated_request;
};
```
@@ -256,6 +257,29 @@ For details on how all of these different types translate to usable generated
code, see
[documentation for individual target languages](#Generated-Code-For-Target-Languages).
+### Unions
+
+Mojom supports tagged unions using the **union** keyword. A union is a
+collection of fields which may taken the value of any single one of those fields
+at a time. Thus they provide a way to represent a variant value type while
+minimizing storage requirements.
+
+Union fields may be of any type supported by [struct](#Structs) fields. For
+example:
+
+```cpp
+union ExampleUnion {
+ string str;
+ StringPair pair;
+ int64 id;
+ array<uint64, 2> guid;
+ SampleInterface iface;
+};
+```
+
+For details on how unions like this translate to generated bindings code, see
+[documentation for individual target languages](#Generated-Code-For-Target-Languages).
+
### Enumeration Types
Enumeration types may be defined using the **enum** keyword either directly
@@ -348,9 +372,9 @@ interesting attributes supported today.
: The `Sync` attribute may be specified for any interface method which expects
a response. This makes it so that callers of the method can wait
synchronously for a response. See
- [Synchronous Calls](/mojo/public/cpp/bindings#Synchronous-Calls) in the C++
- bindings documentation. Note that sync calls are not currently supported in
- other target languages.
+ [Synchronous Calls](/mojo/public/cpp/bindings/README.md#Synchronous-Calls)
+ in the C++ bindings documentation. Note that sync calls are not currently
+ supported in other target languages.
**`[Extensible]`**
: The `Extensible` attribute may be specified for any enum definition. This
@@ -362,15 +386,23 @@ interesting attributes supported today.
: The `Native` attribute may be specified for an empty struct declaration to
provide a nominal bridge between Mojo IPC and legacy `IPC::ParamTraits` or
`IPC_STRUCT_TRAITS*` macros.
- See [Using Legacy IPC Traits](/ipc#Using-Legacy-IPC-Traits) for more
- details. Note support for this attribute is strictly limited to C++ bindings
- generation.
+ See [Using Legacy IPC Traits](/ipc/README.md#Using-Legacy-IPC-Traits) for
+ more details. Note support for this attribute is strictly limited to C++
+ bindings generation.
**`[MinVersion=N]`**
: The `MinVersion` attribute is used to specify the version at which a given
field, enum value, interface method, or method parameter was introduced.
See [Versioning](#Versioning) for more details.
+**`[EnableIf=value]`**
+: The `EnableIf` attribute is used to conditionally enable definitions when
+ the mojom is parsed. If the `mojom` target in the GN file does not include
+ the matching `value` in the list of `enabled_features`, the definition
+ will be disabled. This is useful for mojom definitions that only make
+ sense on one platform. Note that the `EnableIf` attribute can only be set
+ once per definition.
+
## Generated Code For Target Languages
When the bindings generator successfully processes an input Mojom file, it emits
@@ -378,9 +410,9 @@ corresponding code for each supported target language. For more details on how
Mojom concepts translate to a given target langauge, please refer to the
bindings API documentation for that language:
-* [C++ Bindings](/mojo/public/cpp/bindings)
-* [JavaScript Bindings](/mojo/public/js)
-* [Java Bindings](/mojo/public/java/bindings)
+* [C++ Bindings](/mojo/public/cpp/bindings/README.md)
+* [JavaScript Bindings](/mojo/public/js/README.md)
+* [Java Bindings](/mojo/public/java/bindings/README.md)
## Message Validation
@@ -392,9 +424,11 @@ is added.
If a message fails validation, it is never dispatched. Instead a **connection
error** is raised on the binding object (see
-[C++ Connection Errors](/mojo/public/cpp/bindings#Connection-Errors),
-[Java Connection Errors](/mojo/public/java/bindings#Connection-Errors), or
-[JavaScript Connection Errors](/mojo/public/js#Connection-Errors) for details.)
+[C++ Connection Errors](/mojo/public/cpp/bindings/README.md#Connection-Errors),
+[Java Connection Errors](/mojo/public/java/bindings/README.md#Connection-Errors),
+or
+[JavaScript Connection Errors](/mojo/public/js/README.md#Connection-Errors) for
+details.)
Some baseline level of validation is done automatically for primitive Mojom
types.
@@ -443,9 +477,9 @@ manually encode their own bindings messages.
It's also possible for developers to define custom validation logic for specific
Mojom struct types by exploiting the
-[type mapping](/mojo/public/cpp/bindings#Type-Mapping) system for C++ bindings.
-Messages rejected by custom validation logic trigger the same validation failure
-behavior as the built-in type validation routines.
+[type mapping](/mojo/public/cpp/bindings/README.md#Type-Mapping) system for C++
+bindings. Messages rejected by custom validation logic trigger the same
+validation failure behavior as the built-in type validation routines.
## Associated Interfaces
@@ -461,7 +495,7 @@ more other interfaces, as they allow interfaces to share a single pipe.
Currenly associated interfaces are only supported in generated C++ bindings.
See the documentation for
-[C++ Associated Interfaces](/mojo/public/cpp/bindings#Associated-Interfaces).
+[C++ Associated Interfaces](/mojo/public/cpp/bindings/README.md#Associated-Interfaces).
## Versioning
@@ -598,8 +632,9 @@ assert the remote version from a client handle (*e.g.*, an
`InterfacePtr<T>` in C++ bindings.)
See
-[C++ Versioning Considerations](/mojo/public/cpp/bindings#Versioning-Considerations)
-and [Java Versioning Considerations](/mojo/public/java/bindings#Versioning-Considerations)
+[C++ Versioning Considerations](/mojo/public/cpp/bindings/README.md#Versioning-Considerations)
+and
+[Java Versioning Considerations](/mojo/public/java/bindings/README.md#Versioning-Considerations)
### Versioned Enums
@@ -637,7 +672,7 @@ is strictly for documentation purposes. It has no impact on the generated code.
With extensible enums, bound interface implementations may receive unknown enum
values and will need to deal with them gracefully. See
-[C++ Versioning Considerations](/mojo/public/cpp/bindings#Versioning-Considerations)
+[C++ Versioning Considerations](/mojo/public/cpp/bindings/README.md#Versioning-Considerations)
for details.
## Grammar Reference
diff --git a/mojo/public/tools/bindings/blink_bindings_configuration.gni b/mojo/public/tools/bindings/blink_bindings_configuration.gni
index bb0fc432a3..990d1337de 100644
--- a/mojo/public/tools/bindings/blink_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/blink_bindings_configuration.gni
@@ -7,10 +7,10 @@ variant = "blink"
for_blink = true
_typemap_imports = [
+ "//device/gamepad/public/cpp/typemaps.gni",
"//mojo/public/cpp/bindings/tests/blink_typemaps.gni",
- "//third_party/WebKit/Source/platform/mojo/blink_typemaps.gni",
- "//third_party/WebKit/public/blink_typemaps.gni",
- "//third_party/WebKit/public/public_typemaps.gni",
+ "//third_party/blink/renderer/platform/mojo/blink_typemaps.gni",
+ "//third_party/blink/public/blink_typemaps.gni",
]
_typemaps = []
@@ -24,10 +24,13 @@ foreach(typemap_import, _typemap_imports) {
typemaps = []
foreach(typemap, _typemaps) {
- typemaps += [ {
- filename = typemap
- config = read_file(typemap, "scope")
- } ]
+ typemaps += [
+ {
+ filename = typemap
+ config = read_file(typemap, "scope")
+ },
+ ]
}
blacklist = []
+component_macro_suffix = "_BLINK"
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index ca36723fb0..1893db1ac9 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -4,51 +4,63 @@
_typemap_imports = [
"//ash/public/interfaces/typemaps.gni",
- "//cc/ipc/typemaps.gni",
- "//chrome/browser/media/router/mojo/typemaps.gni",
"//chrome/common/extensions/typemaps.gni",
"//chrome/common/importer/typemaps.gni",
+ "//chrome/common/media_router/mojo/typemaps.gni",
"//chrome/typemaps.gni",
+ "//chromecast/common/mojom/typemaps.gni",
+ "//chromeos/typemaps.gni",
+ "//chromeos/services/device_sync/public/mojom/typemaps.gni",
+ "//chromeos/services/secure_channel/public/mojom/typemaps.gni",
"//components/arc/common/typemaps.gni",
"//components/metrics/public/cpp/typemaps.gni",
+ "//components/sync/mojo/typemaps.gni",
"//components/typemaps.gni",
"//content/common/bluetooth/typemaps.gni",
"//content/common/indexed_db/typemaps.gni",
"//content/common/presentation/typemaps.gni",
"//content/common/typemaps.gni",
"//content/public/common/typemaps.gni",
- "//device/bluetooth/public/interfaces/typemaps.gni",
- "//device/gamepad/public/interfaces/typemaps.gni",
- "//device/generic_sensor/public/interfaces/typemaps.gni",
- "//device/usb/public/interfaces/typemaps.gni",
- "//extensions/common/typemaps.gni",
+ "//device/bluetooth/public/mojom/typemaps.gni",
+ "//device/bluetooth/public/mojom/test/typemaps.gni",
+ "//device/gamepad/public/cpp/typemaps.gni",
"//gpu/ipc/common/typemaps.gni",
- "//media/capture/mojo/typemaps.gni",
+ "//ipc/typemaps.gni",
+ "//media/capture/mojom/typemaps.gni",
"//media/mojo/interfaces/typemaps.gni",
- "//mojo/common/typemaps.gni",
+ "//mojo/public/cpp/base/typemaps.gni",
"//mojo/public/cpp/bindings/tests/chromium_typemaps.gni",
"//net/interfaces/typemaps.gni",
+ "//sandbox/mac/mojom/typemaps.gni",
+ "//services/audio/public/cpp/typemaps.gni",
+ "//services/device/public/mojom/typemaps.gni",
+ "//services/identity/public/cpp/typemaps.gni",
+ "//services/network/public/cpp/typemaps.gni",
"//services/preferences/public/cpp/typemaps.gni",
+ "//services/proxy_resolver/public/cpp/typemaps.gni",
"//services/resource_coordinator/public/cpp/typemaps.gni",
"//services/service_manager/public/cpp/typemaps.gni",
- "//services/ui/gpu/interfaces/typemaps.gni",
"//services/ui/public/interfaces/cursor/typemaps.gni",
"//services/ui/public/interfaces/ime/typemaps.gni",
- "//services/video_capture/public/interfaces/typemaps.gni",
+ "//services/viz/privileged/cpp/typemaps.gni",
+ "//services/viz/privileged/interfaces/compositing/typemaps.gni",
+ "//services/viz/public/cpp/compositing/typemaps.gni",
+ "//services/viz/public/cpp/hit_test/typemaps.gni",
"//skia/public/interfaces/typemaps.gni",
- "//third_party/WebKit/public/public_typemaps.gni",
+ "//third_party/blink/common/typemaps.gni",
+ "//third_party/blink/public/public_typemaps.gni",
+ "//ui/accessibility/mojom/typemaps.gni",
"//ui/base/mojo/typemaps.gni",
"//ui/display/mojo/typemaps.gni",
"//ui/events/devices/mojo/typemaps.gni",
"//ui/events/mojo/typemaps.gni",
"//ui/gfx/typemaps.gni",
"//ui/latency/mojo/typemaps.gni",
- "//ui/message_center/mojo/typemaps.gni",
- "//url/mojo/typemaps.gni",
+ "//ui/ozone/public/interfaces/typemaps.gni",
+ "//ui/message_center/public/mojo/typemaps.gni",
+ "//url/mojom/typemaps.gni",
]
-_typemap_imports_mac = [ "//content/common/typemaps_mac.gni" ]
-
_typemaps = []
foreach(typemap_import, _typemap_imports) {
# Avoid reassignment error by assigning to empty scope first.
@@ -60,24 +72,12 @@ foreach(typemap_import, _typemap_imports) {
typemaps = []
foreach(typemap, _typemaps) {
- typemaps += [ {
- filename = typemap
- config = read_file(typemap, "scope")
- } ]
+ typemaps += [
+ {
+ filename = typemap
+ config = read_file(typemap, "scope")
+ },
+ ]
}
-_typemaps_mac = []
-foreach(typemap_import, _typemap_imports_mac) {
- _imported = {
- }
- _imported = read_file(typemap_import, "scope")
- _typemaps_mac += _imported.typemaps
-}
-
-typemaps_mac = []
-foreach(typemap, _typemaps_mac) {
- typemaps_mac += [ {
- filename = typemap
- config = read_file(typemap, "scope")
- } ]
-}
+component_macro_suffix = ""
diff --git a/mojo/public/tools/bindings/gen_data_files_list.py b/mojo/public/tools/bindings/gen_data_files_list.py
new file mode 100644
index 0000000000..8d40173fac
--- /dev/null
+++ b/mojo/public/tools/bindings/gen_data_files_list.py
@@ -0,0 +1,48 @@
+# Copyright 2017 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 a list of all files in a directory.
+
+This script takes in a directory and an output file name as input.
+It then reads the directory and creates a list of all file names
+in that directory. The list is written to the output file.
+There is also an option to pass in '-p' or '--pattern'
+which will check each file name against a regular expression
+pattern that is passed in. Only files which match the regex
+will be written to the list.
+"""
+
+import os
+import re
+import sys
+
+from cStringIO import StringIO
+from optparse import OptionParser
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ "pylib"))
+
+from mojom.generate.generator import WriteFile
+
+
+def main():
+ parser = OptionParser()
+ parser.add_option('-d', '--directory', help='Read files from DIRECTORY')
+ parser.add_option('-o', '--output', help='Write list to FILE')
+ parser.add_option('-p',
+ '--pattern',
+ help='Only reads files that name matches PATTERN',
+ default=".")
+ (options, _) = parser.parse_args()
+ pattern = re.compile(options.pattern)
+ files = [f for f in os.listdir(options.directory) if pattern.match(f)]
+
+ stream = StringIO()
+ for f in files:
+ print >> stream, f
+
+ WriteFile(stream.getvalue(), options.output)
+ stream.close()
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/mojo/public/tools/bindings/generate_type_mappings.py b/mojo/public/tools/bindings/generate_type_mappings.py
index 824f8045ab..ee55e99404 100755
--- a/mojo/public/tools/bindings/generate_type_mappings.py
+++ b/mojo/public/tools/bindings/generate_type_mappings.py
@@ -61,7 +61,12 @@ import argparse
import json
import os
import re
+import sys
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ "pylib"))
+
+from mojom.generate.generator import WriteFile
def ReadTypemap(path):
with open(path) as f:
@@ -106,14 +111,17 @@ def ParseTypemap(typemap):
(result[mojom_type]['typename'], native_type, mojom_type))
result[mojom_type] = {
+ 'public_headers': values['public_headers'],
+ 'traits_headers': values['traits_headers'],
'typename': native_type,
- 'non_copyable_non_movable': 'non_copyable_non_movable' in attributes,
- 'move_only': 'move_only' in attributes,
+
+ # Attributes supported for individual mappings.
'copyable_pass_by_value': 'copyable_pass_by_value' in attributes,
- 'nullable_is_same_type': 'nullable_is_same_type' in attributes,
+ 'force_serialize': 'force_serialize' in attributes,
'hashable': 'hashable' in attributes,
- 'public_headers': values['public_headers'],
- 'traits_headers': values['traits_headers'],
+ 'move_only': 'move_only' in attributes,
+ 'non_copyable_non_movable': 'non_copyable_non_movable' in attributes,
+ 'nullable_is_same_type': 'nullable_is_same_type' in attributes,
}
return result
@@ -140,8 +148,8 @@ def main():
raise IOError('Missing dependencies: %s' % ', '.join(missing))
for path in params.dependency:
typemaps.update(ReadTypemap(path))
- with open(params.output, 'w') as f:
- json.dump({'c++': typemaps}, f, indent=2)
+
+ WriteFile(json.dumps({'c++': typemaps}, indent=2), params.output)
if __name__ == '__main__':
diff --git a/mojo/public/tools/bindings/generators/__init__.py b/mojo/public/tools/bindings/generators/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/__init__.py
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
index f0d503e5e0..d2416ab8c0 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
@@ -12,6 +12,12 @@ enum class {{enum_name}} : int32_t {
{{field.name}},
{%- endif %}
{%- endfor %}
+{%- if enum.min_value is not none %}
+ kMinValue = {{enum.min_value}},
+{%- endif %}
+{%- if enum.max_value is not none %}
+ kMaxValue = {{enum.max_value}},
+{%- endif %}
};
inline std::ostream& operator<<(std::ostream& os, {{enum_name}} value) {
@@ -94,14 +100,14 @@ struct hash<{{enum_name}}>
{%- set deleted_value_unused = "false" if empty_value in enum|all_enum_values else "true" %}
namespace WTF {
struct {{hash_fn_name}} {
- static unsigned hash(const {{enum_name}}& value) {
- typedef base::underlying_type<{{enum_name}}>::type utype;
- return DefaultHash<utype>::Hash().hash(static_cast<utype>(value));
+ static unsigned GetHash(const {{enum_name}}& value) {
+ using utype = std::underlying_type<{{enum_name}}>::type;
+ return DefaultHash<utype>::Hash().GetHash(static_cast<utype>(value));
}
- static bool equal(const {{enum_name}}& left, const {{enum_name}}& right) {
+ static bool Equal(const {{enum_name}}& left, const {{enum_name}}& right) {
return left == right;
}
- static const bool safeToCompareToEmptyOrDeleted = true;
+ static const bool safe_to_compare_to_empty_or_deleted = true;
};
template <>
@@ -117,13 +123,13 @@ struct HashTraits<{{enum_name}}>
static_assert({{deleted_value_unused}},
"{{deleted_value}} is a reserved enum value");
static const bool hasIsEmptyValueFunction = true;
- static bool isEmptyValue(const {{enum_name}}& value) {
+ static bool IsEmptyValue(const {{enum_name}}& value) {
return value == static_cast<{{enum_name}}>({{empty_value}});
}
- static void constructDeletedValue({{enum_name}}& slot, bool) {
+ static void ConstructDeletedValue({{enum_name}}& slot, bool) {
slot = static_cast<{{enum_name}}>({{deleted_value}});
}
- static bool isDeletedValue(const {{enum_name}}& value) {
+ static bool IsDeletedValue(const {{enum_name}}& value) {
return value == static_cast<{{enum_name}}>({{deleted_value}});
}
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
index 7f6497475a..193d380e73 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
@@ -63,3 +63,29 @@ class {{export_attribute}} {{interface.name}}
virtual void {{method.name}}({{interface_macros.declare_request_params("", method, use_once_callback)}}) = 0;
{%- endfor %}
};
+
+{#--- Testing interceptor #}
+class {{export_attribute}} {{interface.name}}InterceptorForTesting : public {{interface.name}} {
+ virtual {{interface.name}}* GetForwardingInterface() = 0;
+
+{%- for method in interface.methods %}
+ void {{method.name}}({{interface_macros.declare_request_params("", method, use_once_callback)}}) override;
+{%- endfor %}
+};
+
+{#--- Async wait helper for testing #}
+class {{export_attribute}} {{interface.name}}AsyncWaiter {
+ public:
+ explicit {{interface.name}}AsyncWaiter({{interface.name}}* proxy);
+ ~{{interface.name}}AsyncWaiter();
+
+{%- for method in interface.methods if method.response_parameters != None %}
+ void {{method.name}}(
+ {{interface_macros.declare_sync_method_params("", method)}});
+{%- endfor %}
+
+ private:
+ {{interface.name}}* const proxy_;
+
+ DISALLOW_COPY_AND_ASSIGN({{interface.name}}AsyncWaiter);
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
index aba18380af..72c3101c14 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -7,12 +7,10 @@
{%- macro alloc_params(struct, params, message, description) %}
mojo::internal::SerializationContext serialization_context;
- serialization_context.handles.Swap(({{message}})->mutable_handles());
- serialization_context.associated_endpoint_handles.swap(
- *({{message}})->mutable_associated_endpoint_handles());
+ serialization_context.TakeHandlesFromMessage({{message}});
bool success = true;
{%- for param in struct.packed.packed_fields_in_ordinal_order %}
- {{param.field.kind|cpp_wrapper_type}} p_{{param.field.name}}{};
+ {{param.field.kind|cpp_wrapper_call_type}} p_{{param.field.name}}{};
{%- endfor %}
{{struct.name}}DataView input_data_view({{params}}, &serialization_context);
{{struct_macros.deserialize(struct, "input_data_view", "p_%s", "success")}}
@@ -32,24 +30,15 @@ std::move(p_{{param.name}})
{%- endfor %}
{%- endmacro %}
-{%- macro build_message(struct, input_pattern, struct_display_name,
- serialization_context) -%}
- {{struct_macros.serialize(struct, struct_display_name, input_pattern,
- "params", "builder.buffer()",
- serialization_context)}}
- ({{serialization_context}})->handles.Swap(
- builder.message()->mutable_handles());
- ({{serialization_context}})->associated_endpoint_handles.swap(
- *builder.message()->mutable_associated_endpoint_handles());
-{%- endmacro %}
-
{#--- Begin #}
-const char {{class_name}}::Name_[] = "{{namespace_as_string}}::{{class_name}}";
+const char {{class_name}}::Name_[] = "{{namespace}}.{{class_name}}";
{#--- Constants #}
{%- for constant in interface.constants %}
{%- if constant.kind|is_string_kind %}
const char {{interface.name}}::{{constant.name}}[] = {{constant|constant_value}};
+{%- else %}
+constexpr {{constant.kind|cpp_pod_type}} {{interface.name}}::{{constant.name}};
{%- endif %}
{%- endfor %}
@@ -73,7 +62,7 @@ class {{class_name}}_{{method.name}}_HandleSyncResponse
{{class_name}}_{{method.name}}_HandleSyncResponse(
bool* result
{%- for param in method.response_parameters -%}
- , {{param.kind|cpp_wrapper_type}}* out_{{param.name}}
+ , {{param.kind|cpp_wrapper_call_type}}* out_{{param.name}}
{%- endfor %})
: result_(result)
{%- for param in method.response_parameters -%}
@@ -85,27 +74,10 @@ class {{class_name}}_{{method.name}}_HandleSyncResponse
private:
bool* result_;
{%- for param in method.response_parameters %}
- {{param.kind|cpp_wrapper_type}}* out_{{param.name}}_;
+ {{param.kind|cpp_wrapper_call_type}}* out_{{param.name}}_;
{%- endfor -%}
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_HandleSyncResponse);
};
-bool {{class_name}}_{{method.name}}_HandleSyncResponse::Accept(
- mojo::Message* message) {
- internal::{{class_name}}_{{method.name}}_ResponseParams_Data* params =
- reinterpret_cast<internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
- message->mutable_payload());
-
-{%- set desc = class_name~"::"~method.name~" response" %}
- {{alloc_params(method.response_param_struct, "params", "message", desc)}}
-
-{%- for param in method.response_parameters %}
- *out_{{param.name}}_ = std::move(p_{{param.name}});
-{%- endfor %}
- mojo::internal::SyncMessageResponseSetup::SetCurrentSyncResponseMessage(
- message);
- *result_ = true;
- return true;
-}
{%- endif %}
class {{class_name}}_{{method.name}}_ForwardToCallback
@@ -124,20 +96,6 @@ class {{class_name}}_{{method.name}}_ForwardToCallback
{{class_name}}::{{method.name}}Callback callback_;
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ForwardToCallback);
};
-bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
- mojo::Message* message) {
- internal::{{class_name}}_{{method.name}}_ResponseParams_Data* params =
- reinterpret_cast<internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
- message->mutable_payload());
-
-{%- set desc = class_name~"::"~method.name~" response" %}
- {{alloc_params(method.response_param_struct, "params", "message", desc)}}
- if (!callback_.is_null()) {
- mojo::internal::MessageDispatchContext context(message);
- std::move(callback_).Run({{pass_params(method.response_parameters)}});
- }
- return true;
-}
{%- endif %}
{%- endfor %}
@@ -153,62 +111,94 @@ bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
{%- set params_struct = method.param_struct %}
{%- set params_description =
"%s.%s request"|format(interface.name, method.name) %}
+{%- set message_typename = "%s_%s_Message"|format(proxy_name, method.name) %}
+
+{%- if method|method_supports_lazy_serialization %}
+{{interface_macros.define_message_type(
+ interface, message_typename, message_name, False, method, method.parameters,
+ params_struct, params_description, use_once_callback)}}
+{%- endif %}
+
{%- if method.sync %}
bool {{proxy_name}}::{{method.name}}(
{{interface_macros.declare_sync_method_params("param_", method)}}) {
- mojo::internal::SerializationContext serialization_context;
- {{struct_macros.get_serialized_size(params_struct, "param_%s",
- "&serialization_context")}}
-
- mojo::internal::MessageBuilder builder(
- {{message_name}},
- mojo::Message::kFlagIsSync | mojo::Message::kFlagExpectsResponse,
- size, serialization_context.associated_endpoint_count);
+#if BUILDFLAG(MOJO_TRACE_ENABLED)
+ TRACE_EVENT0("mojom", "{{namespace_as_string}}::{{class_name}}::{{method.name}}");
+#endif
+ const bool kExpectsResponse = true;
+ const bool kIsSync = true;
+{%- if method|method_supports_lazy_serialization %}
+ const bool kSerialize = receiver_->PrefersSerializedMessages();
+ auto message = {{message_typename}}::Build(
+ kSerialize, kExpectsResponse, kIsSync
+{%- for param in method.parameters -%}
+ , std::move(param_{{param.name}})
+{%- endfor %});
+{%- else %}
+ {{interface_macros.build_message_flags(False, "kIsSync", "kExpectsResponse",
+ "kFlags")}}
+ {{interface_macros.build_serialized_message(
+ message_name, "param_%s", params_struct, params_description, "kFlags",
+ "message")}}
+{%- endif %}
- {{build_message(params_struct, "param_%s", params_description,
- "&serialization_context")}}
+#if defined(ENABLE_IPC_FUZZER)
+ message.set_interface_name({{class_name}}::Name_);
+ message.set_method_name("{{method.name}}");
+#endif
bool result = false;
std::unique_ptr<mojo::MessageReceiver> responder(
new {{class_name}}_{{method.name}}_HandleSyncResponse(
&result
{%- for param in method.response_parameters -%}
- , param_{{param.name}}
+ , out_param_{{param.name}}
{%- endfor %}));
- ignore_result(receiver_->AcceptWithResponder(builder.message(),
- std::move(responder)));
+ ignore_result(receiver_->AcceptWithResponder(&message, std::move(responder)));
return result;
}
{%- endif %}
void {{proxy_name}}::{{method.name}}(
{{interface_macros.declare_request_params("in_", method, use_once_callback)}}) {
- mojo::internal::SerializationContext serialization_context;
- {{struct_macros.get_serialized_size(params_struct, "in_%s",
- "&serialization_context")}}
-
+#if BUILDFLAG(MOJO_TRACE_ENABLED)
+ TRACE_EVENT0("mojom", "{{namespace_as_string}}::{{class_name}}::{{method.name}}");
+#endif
{%- if method.response_parameters != None %}
- constexpr uint32_t kFlags = mojo::Message::kFlagExpectsResponse;
+ const bool kExpectsResponse = true;
{%- else %}
- constexpr uint32_t kFlags = 0;
+ const bool kExpectsResponse = false;
{%- endif %}
- mojo::internal::MessageBuilder builder(
- {{message_name}}, kFlags, size,
- serialization_context.associated_endpoint_count);
+ const bool kIsSync = false;
+{%- if method|method_supports_lazy_serialization %}
+ const bool kSerialize = receiver_->PrefersSerializedMessages();
+ auto message = {{message_typename}}::Build(
+ kSerialize, kExpectsResponse, kIsSync
+{%- for param in method.parameters -%}
+ , std::move(in_{{param.name}})
+{%- endfor %});
+{%- else %}
+ {{interface_macros.build_message_flags(False, "kIsSync", "kExpectsResponse",
+ "kFlags")}}
+ {{interface_macros.build_serialized_message(
+ message_name, "in_%s", params_struct, params_description, "kFlags",
+ "message")}}
+{%- endif %}
- {{build_message(params_struct, "in_%s", params_description,
- "&serialization_context")}}
+#if defined(ENABLE_IPC_FUZZER)
+ message.set_interface_name({{class_name}}::Name_);
+ message.set_method_name("{{method.name}}");
+#endif
{%- if method.response_parameters != None %}
std::unique_ptr<mojo::MessageReceiver> responder(
new {{class_name}}_{{method.name}}_ForwardToCallback(
std::move(callback)));
- ignore_result(receiver_->AcceptWithResponder(builder.message(),
- std::move(responder)));
+ ignore_result(receiver_->AcceptWithResponder(&message, std::move(responder)));
{%- else %}
// This return value may be ignored as false implies the Connector has
// encountered an error, which will be visible through other means.
- ignore_result(receiver_->Accept(builder.message()));
+ ignore_result(receiver_->Accept(&message));
{%- endif %}
}
{%- endfor %}
@@ -221,6 +211,8 @@ void {{proxy_name}}::{{method.name}}(
{%- set response_params_struct = method.response_param_struct %}
{%- set params_description =
"%s.%s response"|format(interface.name, method.name) %}
+{%- set response_message_typename =
+ "%s_%s_Response_Message"|format(interface.name, method.name) %}
class {{class_name}}_{{method.name}}_ProxyToResponder {
public:
static {{class_name}}::{{method.name}}Callback CreateCallback(
@@ -230,17 +222,23 @@ class {{class_name}}_{{method.name}}_ProxyToResponder {
std::unique_ptr<{{class_name}}_{{method.name}}_ProxyToResponder> proxy(
new {{class_name}}_{{method.name}}_ProxyToResponder(
request_id, is_sync, std::move(responder)));
+{%- if use_once_callback %}
+ return base::BindOnce(&{{class_name}}_{{method.name}}_ProxyToResponder::Run,
+ std::move(proxy));
+{%- else %}
return base::Bind(&{{class_name}}_{{method.name}}_ProxyToResponder::Run,
base::Passed(&proxy));
+{%- endif %}
}
~{{class_name}}_{{method.name}}_ProxyToResponder() {
#if DCHECK_IS_ON()
if (responder_) {
- // Is the Service destroying the callback without running it
- // and without first closing the pipe?
- responder_->DCheckInvalid("The callback passed to "
- "{{class_name}}::{{method.name}}() was never run.");
+ // If we're being destroyed without being run, we want to ensure the
+ // binding endpoint has been closed. This checks for that asynchronously.
+ // We pass a bound generated callback to handle the response so that any
+ // resulting DCHECK stack will have useful interface type information.
+ responder_->IsConnectedAsync(base::BindOnce(&OnIsConnectedComplete));
}
#endif
// If the Callback was dropped then deleting the responder will close
@@ -258,9 +256,18 @@ class {{class_name}}_{{method.name}}_ProxyToResponder {
responder_(std::move(responder)) {
}
+#if DCHECK_IS_ON()
+ static void OnIsConnectedComplete(bool connected) {
+ DCHECK(!connected)
+ << "{{class_name}}::{{method.name}}Callback was destroyed without "
+ << "first either being run or its corresponding binding being closed. "
+ << "It is an error to drop response callbacks which still correspond "
+ << "to an open interface pipe.";
+ }
+#endif
+
void Run(
- {{interface_macros.declare_responder_params(
- "in_", method.response_parameters, for_blink)}});
+ {{interface_macros.declare_params("in_", method.response_parameters)}});
uint64_t request_id_;
bool is_sync_;
@@ -269,29 +276,128 @@ class {{class_name}}_{{method.name}}_ProxyToResponder {
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ProxyToResponder);
};
+{%- if method|method_supports_lazy_serialization %}
+{{interface_macros.define_message_type(
+ interface, response_message_typename, message_name, True, method,
+ method.response_parameters, response_params_struct, params_description,
+ use_once_callback)}}
+{%- endif %}
+
+bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
+ mojo::Message* message) {
+#if BUILDFLAG(MOJO_TRACE_ENABLED)
+ TRACE_EVENT1("mojom", "{{namespace_as_string}}::{{class_name}}::{{method.name}}Callback",
+ "message", message->name());
+#endif
+ mojo::internal::MessageDispatchContext dispatch_context(message);
+{%- if method|method_supports_lazy_serialization %}
+ if (!message->is_serialized()) {
+ auto context =
+ message->TakeUnserializedContext<{{response_message_typename}}>();
+ if (!context) {
+ // The Message was not of the expected type. It may be a valid message
+ // which was build using a different variant of these bindings. Force
+ // serialization before dispatch in this case.
+ message->SerializeIfNecessary();
+ } else {
+ if (!callback_.is_null())
+ context->Dispatch(&callback_);
+ return true;
+ }
+ }
+{%- endif %}
+
+ DCHECK(message->is_serialized());
+ internal::{{class_name}}_{{method.name}}_ResponseParams_Data* params =
+ reinterpret_cast<
+ internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
+ message->mutable_payload());
+
+{%- set desc = class_name~"::"~method.name~" response" %}
+ {{alloc_params(method.response_param_struct, "params", "message", desc)}}
+ if (!callback_.is_null())
+ std::move(callback_).Run({{pass_params(method.response_parameters)}});
+ return true;
+}
+
void {{class_name}}_{{method.name}}_ProxyToResponder::Run(
- {{interface_macros.declare_responder_params(
- "in_", method.response_parameters, for_blink)}}) {
- mojo::internal::SerializationContext serialization_context;
- {{struct_macros.get_serialized_size(response_params_struct, "in_%s",
- "&serialization_context")}}
-
- uint32_t flags = (is_sync_ ? mojo::Message::kFlagIsSync : 0) |
- mojo::Message::kFlagIsResponse;
- mojo::internal::MessageBuilder builder(
- {{message_name}}, flags, size,
- serialization_context.associated_endpoint_count);
- builder.message()->set_request_id(request_id_);
-
- {{build_message(response_params_struct, "in_%s", params_description,
- "&serialization_context")}}
- ignore_result(responder_->Accept(builder.message()));
+ {{interface_macros.declare_params("in_", method.response_parameters)}}) {
+{%- if method|method_supports_lazy_serialization %}
+ const bool kSerialize = responder_->PrefersSerializedMessages();
+ auto message = {{response_message_typename}}::Build(kSerialize, is_sync_
+{%- for param in method.response_parameters -%}
+ , std::move(in_{{param.name}})
+{%- endfor %});
+{%- else %}
+ {{interface_macros.build_message_flags(True, "is_sync_", "false", "kFlags")}}
+ {{interface_macros.build_serialized_message(
+ message_name, "in_%s", response_params_struct,
+ response_params_description, "kFlags", "message")}}
+{%- endif %}
+
+#if BUILDFLAG(MOJO_TRACE_ENABLED)
+ TRACE_EVENT1("mojom", "(Impl){{namespace_as_string}}::{{class_name}}::{{method.name}}Callback",
+ "message", message.name());
+#endif
+
+#if defined(ENABLE_IPC_FUZZER)
+ message.set_interface_name({{class_name}}::Name_);
+ message.set_method_name("{{method.name}}");
+#endif
+
+ message.set_request_id(request_id_);
+ ignore_result(responder_->Accept(&message));
// TODO(darin): Accept() returning false indicates a malformed message, and
// that may be good reason to close the connection. However, we don't have a
// way to do that from here. We should add a way.
responder_ = nullptr;
}
{%- endif -%}
+
+{%- if method.sync %}
+bool {{class_name}}_{{method.name}}_HandleSyncResponse::Accept(
+ mojo::Message* message) {
+{%- if method|method_supports_lazy_serialization %}
+ if (!message->is_serialized()) {
+ auto context =
+ message->TakeUnserializedContext<{{response_message_typename}}>();
+ if (!context) {
+ // The Message was not of the expected type. It may be a valid message
+ // which was built using a different variant of these bindings. Force
+ // serialization before dispatch in this case.
+ message->SerializeIfNecessary();
+ } else {
+ context->HandleSyncResponse(
+{%- for param in method.response_parameters %}
+ out_{{param.name}}_
+{%- if not loop.last -%}, {% endif -%}
+{%- endfor %});
+ *result_ = true;
+ mojo::internal::SyncMessageResponseSetup::SetCurrentSyncResponseMessage(
+ message);
+ return true;
+ }
+ }
+{%- endif %}
+
+ DCHECK(message->is_serialized());
+ internal::{{class_name}}_{{method.name}}_ResponseParams_Data* params =
+ reinterpret_cast<internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
+ message->mutable_payload());
+
+{%- set desc = class_name~"::"~method.name~" response" %}
+ {{alloc_params(method.response_param_struct, "params", "message", desc)}}
+
+{%- for param in method.response_parameters %}
+ *out_{{param.name}}_ = std::move(p_{{param.name}});
+{%- endfor %}
+ mojo::internal::SyncMessageResponseSetup::SetCurrentSyncResponseMessage(
+ message);
+ *result_ = true;
+ return true;
+}
+{%- endif %}
+
{%- endfor %}
{#--- StubDispatch definition #}
@@ -304,7 +410,29 @@ bool {{class_name}}StubDispatch::Accept(
switch (message->header()->name) {
{%- for method in interface.methods %}
case internal::k{{class_name}}_{{method.name}}_Name: {
+#if BUILDFLAG(MOJO_TRACE_ENABLED)
+ TRACE_EVENT1("mojom", "(Impl){{namespace_as_string}}::{{class_name}}::{{method.name}}",
+ "message", message->name());
+#endif
{%- if method.response_parameters == None %}
+ mojo::internal::MessageDispatchContext context(message);
+{%- if method|method_supports_lazy_serialization %}
+ if (!message->is_serialized()) {
+ auto context = message->TakeUnserializedContext<
+ {{proxy_name}}_{{method.name}}_Message>();
+ if (!context) {
+ // The Message was not of the expected type. It may be a valid message
+ // which was serialized using a different variant of these bindings.
+ // Force serialization before dispatch in this case.
+ message->SerializeIfNecessary();
+ } else {
+ context->Dispatch(impl);
+ return true;
+ }
+ }
+{%- endif %}
+
+ DCHECK(message->is_serialized());
internal::{{class_name}}_{{method.name}}_Params_Data* params =
reinterpret_cast<internal::{{class_name}}_{{method.name}}_Params_Data*>(
message->mutable_payload());
@@ -314,8 +442,6 @@ bool {{class_name}}StubDispatch::Accept(
indent(4)}}
// A null |impl| means no implementation was bound.
assert(impl);
- TRACE_EVENT0("mojom", "{{class_name}}::{{method.name}}");
- mojo::internal::MessageDispatchContext context(message);
impl->{{method.name}}({{pass_params(method.parameters)}});
return true;
{%- else %}
@@ -337,10 +463,37 @@ bool {{class_name}}StubDispatch::AcceptWithResponder(
switch (message->header()->name) {
{%- for method in interface.methods %}
case internal::k{{class_name}}_{{method.name}}_Name: {
+#if BUILDFLAG(MOJO_TRACE_ENABLED)
+ TRACE_EVENT1("mojom", "(Impl){{namespace_as_string}}::{{class_name}}::{{method.name}}",
+ "message", message->name());
+#endif
{%- if method.response_parameters != None %}
+ mojo::internal::MessageDispatchContext context(message);
+{%- if method|method_supports_lazy_serialization %}
+ if (!message->is_serialized()) {
+ auto context = message->TakeUnserializedContext<
+ {{proxy_name}}_{{method.name}}_Message>();
+ if (!context) {
+ // The Message was not of the expected type. It may be a valid message
+ // which was built using a different variant of these bindings. Force
+ // serialization before dispatch in this case.
+ message->SerializeIfNecessary();
+ } else {
+ {{class_name}}::{{method.name}}Callback callback =
+ {{class_name}}_{{method.name}}_ProxyToResponder::CreateCallback(
+ message->request_id(),
+ message->has_flag(mojo::Message::kFlagIsSync),
+ std::move(responder));
+ context->Dispatch(impl, std::move(callback));
+ return true;
+ }
+ }
+{%- endif %}
+
internal::{{class_name}}_{{method.name}}_Params_Data* params =
- reinterpret_cast<internal::{{class_name}}_{{method.name}}_Params_Data*>(
- message->mutable_payload());
+ reinterpret_cast<
+ internal::{{class_name}}_{{method.name}}_Params_Data*>(
+ message->mutable_payload());
{%- set desc = class_name~"::"~method.name %}
{{alloc_params(method.param_struct, "params", "message", desc)|
@@ -352,8 +505,6 @@ bool {{class_name}}StubDispatch::AcceptWithResponder(
std::move(responder));
// A null |impl| means no implementation was bound.
assert(impl);
- TRACE_EVENT0("mojom", "{{class_name}}::{{method.name}}");
- mojo::internal::MessageDispatchContext context(message);
impl->{{method.name}}(
{%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}std::move(callback));
return true;
@@ -370,8 +521,10 @@ bool {{class_name}}StubDispatch::AcceptWithResponder(
{#--- Request validator definitions #}
bool {{class_name}}RequestValidator::Accept(mojo::Message* message) {
- if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
+ if (!message->is_serialized() ||
+ mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
return true;
+ }
mojo::internal::ValidationContext validation_context(
message->payload(), message->payload_num_bytes(),
@@ -414,8 +567,10 @@ bool {{class_name}}RequestValidator::Accept(mojo::Message* message) {
{#--- Response validator definitions #}
{% if interface|has_callbacks %}
bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) {
- if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
+ if (!message->is_serialized() ||
+ mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
return true;
+ }
mojo::internal::ValidationContext validation_context(
message->payload(), message->payload_num_bytes(),
@@ -446,3 +601,57 @@ bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) {
return false;
}
{%- endif -%}
+
+{#--- Testing interceptor #}
+{%- for method in interface.methods %}
+void {{interface.name}}InterceptorForTesting::{{method.name}}({{interface_macros.declare_request_params("", method, use_once_callback)}}) {
+ GetForwardingInterface()->{{method.name}}(
+ {%- for param in method.parameters -%}
+ std::move({{param.name}}){%- if not loop.last %}, {% endif %}
+ {%- endfor %}
+ {%- if method.response_parameters != None -%}
+ {%- if method.parameters %}, {% endif -%}
+ std::move(callback)
+ {%- endif -%}
+ );
+}
+{%- endfor %}
+
+{#--- Async wait helper for testing #}
+{{interface.name}}AsyncWaiter::{{interface.name}}AsyncWaiter(
+ {{interface.name}}* proxy) : proxy_(proxy) {}
+
+{{interface.name}}AsyncWaiter::~{{interface.name}}AsyncWaiter() = default;
+
+{% for method in interface.methods if method.response_parameters != None -%}
+void {{interface.name}}AsyncWaiter::{{method.name}}(
+ {{interface_macros.declare_sync_method_params("", method)}}) {
+ base::RunLoop loop;
+ proxy_->{{method.name}}(
+{%- for param in method.parameters -%}
+ std::move({{param.name}}),
+{%- endfor %}
+{%- if use_once_callback %}
+ base::BindOnce(
+{%- else %}
+ base::Bind(
+{%- endif %}
+ [](base::RunLoop* loop
+{%- for param in method.response_parameters -%},
+ {{param.kind|cpp_wrapper_call_type}}* out_{{param.name}}
+{% endfor -%}
+{%- for param in method.response_parameters -%},
+ {{param.kind|cpp_wrapper_param_type}} {{param.name}}
+{%- endfor %}) {
+{%- for param in method.response_parameters -%}
+ *out_{{param.name}} = std::move({{param.name}});
+{%- endfor %}
+ loop->Quit();
+ },
+ &loop
+{%- for param in method.response_parameters -%},
+ out_{{param.name}}
+{%- endfor %}));
+ loop.Run();
+}
+{% endfor %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
index 8649273633..052691dea0 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
@@ -1,11 +1,6 @@
-{%- macro declare_params(prefix, parameters) %}
-{%- for param in parameters -%}
-{{param.kind|cpp_wrapper_param_type}} {{prefix}}{{param.name}}
-{%- if not loop.last %}, {% endif %}
-{%- endfor %}
-{%- endmacro %}
+{%- import "struct_macros.tmpl" as struct_macros %}
-{%- macro declare_responder_params(prefix, parameters, for_blink) %}
+{%- macro declare_params(prefix, parameters) %}
{%- for param in parameters -%}
{{param.kind|cpp_wrapper_param_type}} {{prefix}}{{param.name}}
{%- if not loop.last %}, {% endif %}
@@ -42,8 +37,165 @@ const {{method.name}}Callback& callback
{%- if method.response_parameters %}
{%- if method.parameters %}, {% endif %}
{%- for param in method.response_parameters -%}
-{{param.kind|cpp_wrapper_type}}* {{prefix}}{{param.name}}
+{{param.kind|cpp_wrapper_call_type}}* out_{{prefix}}{{param.name}}
{%- if not loop.last %}, {% endif %}
{%- endfor %}
{%- endif -%}
{%- endmacro -%}
+
+{%- macro build_message_flags(is_response, is_sync_text, expects_response_text,
+ flags_name) %}
+{%- if is_response %}
+ const uint32_t kFlags = mojo::Message::kFlagIsResponse |
+ (({{is_sync_text}}) ? mojo::Message::kFlagIsSync : 0);
+{%- else %}
+ const uint32_t kFlags =
+ (({{expects_response_text}}) ? mojo::Message::kFlagExpectsResponse : 0) |
+ (({{is_sync_text}}) ? mojo::Message::kFlagIsSync : 0);
+{%- endif %}
+{%- endmacro %}
+
+{%- macro build_serialized_message(message_name, param_name_prefix,
+ params_struct, params_description,
+ flags_text, message_object_name) %}
+ mojo::Message {{message_object_name}}(
+ {{message_name}}, {{flags_text}}, 0, 0, nullptr);
+ auto* buffer = {{message_object_name}}.payload_buffer();
+ {{params_struct|get_qualified_name_for_kind(internal=True)}}::BufferWriter
+ params;
+ mojo::internal::SerializationContext serialization_context;
+ {{struct_macros.serialize(params_struct, params_description,
+ param_name_prefix, "params", "buffer",
+ "&serialization_context")}}
+ {{message_object_name}}.AttachHandlesFromSerializationContext(
+ &serialization_context);
+{%- endmacro %}
+
+{%- macro define_message_type(interface, message_typename, message_name,
+ is_response, method, parameters, params_struct,
+ params_description, use_once_callback) -%}
+class {{message_typename}}
+ : public mojo::internal::UnserializedMessageContext {
+ public:
+ static const mojo::internal::UnserializedMessageContext::Tag kMessageTag;
+
+ explicit {{message_typename}}(
+ uint32_t message_flags
+{%- for param in parameters %}
+ , {{param.kind|cpp_wrapper_param_type}} param_{{param.name}}
+{%- endfor %}
+ )
+ : mojo::internal::UnserializedMessageContext(
+ &kMessageTag,
+ {{message_name}},
+ message_flags)
+{%- for param in parameters -%}
+{%- if param.kind|is_interface_kind %}
+ , param_{{param.name}}_(param_{{param.name}}.PassInterface())
+{%- else %}
+ , param_{{param.name}}_(std::move(param_{{param.name}}))
+{%- endif %}
+{%- endfor -%} {}
+ ~{{message_typename}}() override = default;
+
+ static mojo::Message Build(
+ bool serialize,
+{%- if not is_response %}
+ bool expects_response,
+{%- endif %}
+ bool is_sync
+{%- if parameters -%}
+ ,
+ {{declare_params("param_", parameters)}}
+{%- endif %}) {
+
+ {{build_message_flags(is_response, "is_sync", "expects_response",
+ "kFlags")}}
+
+ if (!serialize) {
+ return mojo::Message(std::make_unique<{{message_typename}}>(
+ kFlags
+{%- for param in parameters %}
+ , std::move(param_{{param.name}})
+{%- endfor %}
+ ));
+ }
+
+ DCHECK(serialize);
+ {{build_serialized_message(message_name, "param_%s", params_struct,
+ params_description, "kFlags", "message")}}
+ return message;
+ }
+
+{% if not is_response %}
+ void Dispatch({{interface.name}}* impl
+{%- if method.response_parameters != None -%}
+{%- if use_once_callback -%}
+ , {{interface.name}}::{{method.name}}Callback callback
+{%- else -%}
+ , const {{interface.name}}::{{method.name}}Callback& callback
+{%- endif -%}
+{%- endif -%}) {
+ impl->{{method.name}}(
+{%- for param in parameters -%}
+{%- if param.kind|is_interface_kind %}
+ {{param.kind|get_name_for_kind}}Ptr(std::move(param_{{param.name}}_))
+{%- else %}
+ std::move(param_{{param.name}}_)
+{%- endif %}
+ {%- if not loop.last -%}, {%- endif %}
+{%- endfor %}
+{%- if method.response_parameters != None %}
+ {%- if parameters -%}, {% endif -%}std::move(callback)
+{%- endif -%});
+ }
+{%- else %}
+ void Dispatch({{interface.name}}::{{method.name}}Callback* callback) {
+ std::move(*callback).Run(
+{%- for param in parameters -%}
+{%- if param.kind|is_interface_kind %}
+ {{param.kind|get_name_for_kind}}Ptr(std::move(param_{{param.name}}_))
+{%- else %}
+ std::move(param_{{param.name}}_)
+{%- endif %}
+ {%- if not loop.last -%}, {% endif -%}
+{%- endfor -%});
+ }
+
+{% if method.sync %}
+ void HandleSyncResponse(
+{% for param in parameters %}
+ {{param.kind|cpp_wrapper_call_type}}* out_{{param.name}}
+ {%- if not loop.last -%}, {% endif -%}
+{%- endfor -%}) {
+{% for param in parameters -%}
+{%- if param.kind|is_interface_kind %}
+ out_{{param.name}}->Bind(std::move(param_{{param.name}}_));
+{%- else %}
+ *out_{{param.name}} = std::move(param_{{param.name}}_);
+{%- endif %}
+{% endfor %}
+ }
+{%- endif -%}
+{%- endif %}
+
+ private:
+ // mojo::internal::UnserializedMessageContext:
+ void Serialize(mojo::internal::SerializationContext* serialization_context,
+ mojo::internal::Buffer* buffer) override {
+ {{params_struct|get_qualified_name_for_kind(internal=True)}}::BufferWriter
+ params;
+ {{struct_macros.serialize(params_struct, params_description, "param_%s_",
+ "params", "buffer", "serialization_context")}}
+ }
+
+{%- for param in parameters %}
+ {{param.kind|cpp_wrapper_type}} param_{{param.name}}_;
+{%- endfor %}
+
+ DISALLOW_COPY_AND_ASSIGN({{message_typename}});
+};
+
+const mojo::internal::UnserializedMessageContext::Tag
+{{message_typename}}::kMessageTag = {};
+{%- endmacro -%}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl
index 0a158ec3e8..33baae4dd1 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl
@@ -6,9 +6,9 @@ class {{export_attribute}} {{interface.name}}Proxy
{%- for method in interface.methods %}
{%- if method.sync %}
- bool {{method.name}}({{interface_macros.declare_sync_method_params("", method)}}) override;
+ bool {{method.name}}({{interface_macros.declare_sync_method_params("", method)}}) final;
{%- endif %}
- void {{method.name}}({{interface_macros.declare_request_params("", method, use_once_callback)}}) override;
+ void {{method.name}}({{interface_macros.declare_request_params("", method, use_once_callback)}}) final;
{%- endfor %}
private:
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl
index a00d14886d..6440519b9f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl
@@ -1,4 +1,4 @@
-class {{export_attribute}} {{interface.name}}RequestValidator : public NON_EXPORTED_BASE(mojo::MessageReceiver) {
+class {{export_attribute}} {{interface.name}}RequestValidator : public mojo::MessageReceiver {
public:
bool Accept(mojo::Message* message) override;
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl
index e2caa02c79..759726d997 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl
@@ -1,4 +1,4 @@
-class {{export_attribute}} {{interface.name}}ResponseValidator : public NON_EXPORTED_BASE(mojo::MessageReceiver) {
+class {{export_attribute}} {{interface.name}}ResponseValidator : public mojo::MessageReceiver {
public:
bool Accept(mojo::Message* message) override;
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
index 79ab46f337..7253c0a5a5 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
@@ -10,7 +10,7 @@ class {{export_attribute}} {{interface.name}}StubDispatch {
template <typename ImplRefTraits =
mojo::RawPtrImplRefTraits<{{interface.name}}>>
class {{interface.name}}Stub
- : public NON_EXPORTED_BASE(mojo::MessageReceiverWithResponderStatus) {
+ : public mojo::MessageReceiverWithResponderStatus {
public:
using ImplPointerType = typename ImplRefTraits::PointerType;
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl
index 964b25438e..e32f43bf55 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl
@@ -9,19 +9,24 @@
#ifndef {{header_guard}}
#define {{header_guard}}
-#include <stdint.h>
-
#include "mojo/public/cpp/bindings/lib/array_internal.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/map_data_internal.h"
-#include "mojo/public/cpp/bindings/lib/native_enum_data.h"
-#include "mojo/public/cpp/bindings/lib/native_struct_data.h"
#include "mojo/public/cpp/bindings/lib/buffer.h"
{%- for import in imports %}
-#include "{{import.module.path}}-shared-internal.h"
+#include "{{import.path}}-shared-internal.h"
{%- endfor %}
+{%- if not disallow_native_types %}
+#include "mojo/public/cpp/bindings/lib/native_enum_data.h"
+#include "mojo/public/interfaces/bindings/native_struct.mojom-shared-internal.h"
+{%- endif %}
+
+{%- if export_header %}
+#include "{{export_header}}"
+{%- endif %}
+
namespace mojo {
namespace internal {
class ValidationContext;
@@ -36,7 +41,7 @@ namespace internal {
{#--- Internal forward declarations #}
{%- for struct in structs %}
{%- if struct|is_native_only_kind %}
-using {{struct.name}}_Data = mojo::internal::NativeStruct_Data;
+using {{struct.name}}_Data = mojo::native::internal::NativeStruct_Data;
{%- else %}
class {{struct.name}}_Data;
{%- endif %}
@@ -69,14 +74,13 @@ using {{enum|get_name_for_kind(flatten_nested_kind=True)}}_Data =
{%- for struct in structs %}
{%- if not struct|is_native_only_kind %}
{% include "struct_declaration.tmpl" %}
+{% include "struct_unserialized_message_context.tmpl" %}
{%- endif %}
{%- endfor %}
{#--- Interface parameter definitions #}
{%- for interface in interfaces %}
{%- for method in interface.methods %}
-{%- set method_name = "k%s_%s_Name"|format(interface.name, method.name) %}
-constexpr uint32_t {{method_name}} = {{method.ordinal}};
{%- set struct = method.param_struct %}
{% include "struct_declaration.tmpl" %}
{%- if method.response_parameters != None %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared-message-ids.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared-message-ids.h.tmpl
new file mode 100644
index 0000000000..0b5563c7ad
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared-message-ids.h.tmpl
@@ -0,0 +1,35 @@
+// Copyright 2018 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.
+
+{%- set header_guard = "%s_SHARED_MESSAGE_IDS_H_"|format(
+ module.path|upper|replace("/","_")|replace(".","_")|
+ replace("-", "_")) %}
+
+#ifndef {{header_guard}}
+#define {{header_guard}}
+
+#include <stdint.h>
+
+{%- for namespace in namespaces_as_array %}
+namespace {{namespace}} {
+{%- endfor %}
+
+namespace internal {
+
+{% for interface in interfaces -%}
+{%- for method in interface.methods -%}
+{%- set method_name = "k%s_%s_Name"|format(interface.name, method.name) -%}
+{%- if method.ordinal_comment %}
+// {{method.ordinal_comment}}
+{%- endif %}
+constexpr uint32_t {{method_name}} = {{method.ordinal}};
+{%- endfor %}
+{%- endfor %}
+
+} // namespace internal
+{%- for namespace in namespaces_as_array|reverse %}
+} // namespace {{namespace}}
+{%- endfor %}
+
+#endif // {{header_guard}}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
index 645bb692b0..6004c52138 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
@@ -42,7 +42,6 @@ namespace internal {
{#--- Interface parameter definitions #}
{%- for interface in interfaces %}
{%- for method in interface.methods %}
-{%- set method_name = "k%s_%s_Name"|format(interface.name, method.name) %}
{%- set struct = method.param_struct %}
{% include "struct_definition.tmpl" %}
{%- if method.response_parameters != None %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl
index dd13466de1..1ff771d242 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl
@@ -43,26 +43,38 @@ namespace {{namespace}} {
#include <utility>
#include "base/compiler_specific.h"
+#include "base/containers/flat_map.h"
#include "mojo/public/cpp/bindings/array_data_view.h"
#include "mojo/public/cpp/bindings/enum_traits.h"
#include "mojo/public/cpp/bindings/interface_data_view.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
#include "mojo/public/cpp/bindings/map_data_view.h"
-#include "mojo/public/cpp/bindings/native_enum.h"
-#include "mojo/public/cpp/bindings/native_struct_data_view.h"
#include "mojo/public/cpp/bindings/string_data_view.h"
#include "{{module.path}}-shared-internal.h"
{%- for import in imports %}
-#include "{{import.module.path}}-shared.h"
+#include "{{import.path}}-shared.h"
{%- endfor %}
+{% if not disallow_interfaces -%}
+#include "mojo/public/cpp/bindings/lib/interface_serialization.h"
+{%- endif %}
+
+{% if not disallow_native_types %}
+#include "mojo/public/cpp/bindings/native_enum.h"
+#include "mojo/public/cpp/bindings/lib/native_struct_serialization.h"
+{%- endif %}
+
+{%- if export_header %}
+#include "{{export_header}}"
+{%- endif %}
+
{{namespace_begin()}}
{#--- Struct Forward Declarations -#}
{%- for struct in structs %}
{%- if struct|is_native_only_kind %}
-using {{struct.name}}DataView = mojo::NativeStructDataView;
+using {{struct.name}}DataView = mojo::native::NativeStructDataView;
{%- else %}
class {{struct.name}}DataView;
{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
index 2c66a85f87..16f3bafa82 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
@@ -25,14 +25,17 @@
#include <utility>
#include "base/logging.h"
-#include "base/trace_event/trace_event.h"
-#include "mojo/public/cpp/bindings/lib/message_builder.h"
+#include "base/run_loop.h"
+#include "mojo/public/cpp/bindings/lib/message_internal.h"
#include "mojo/public/cpp/bindings/lib/serialization_util.h"
+#include "mojo/public/cpp/bindings/lib/unserialized_message_context.h"
#include "mojo/public/cpp/bindings/lib/validate_params.h"
#include "mojo/public/cpp/bindings/lib/validation_context.h"
#include "mojo/public/cpp/bindings/lib/validation_errors.h"
#include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h"
+#include "{{module.path}}-shared-message-ids.h"
+
{%- if for_blink %}
#include "mojo/public/cpp/bindings/lib/wtf_serialization.h"
{%- endif %}
@@ -60,6 +63,8 @@ const char {{constant.name}}[] = {{constant|constant_value}};
{%- for constant in struct.constants %}
{%- if constant.kind|is_string_kind %}
const char {{struct.name}}::{{constant.name}}[] = {{constant|constant_value}};
+{%- else %}
+constexpr {{constant.kind|cpp_pod_type}} {{struct.name}}::{{constant.name}};
{%- endif %}
{%- endfor %}
{%- endfor %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
index 804a46b6f8..1537b1c828 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -42,29 +42,23 @@ namespace {{variant}} {
#include "base/callback.h"
#include "base/macros.h"
#include "base/optional.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
-#include "mojo/public/cpp/bindings/associated_interface_request.h"
+
+#include "mojo/public/cpp/bindings/mojo_buildflags.h"
+#if BUILDFLAG(MOJO_TRACE_ENABLED)
+#include "base/trace_event/trace_event.h"
+#endif
#include "mojo/public/cpp/bindings/clone_traits.h"
-#include "mojo/public/cpp/bindings/interface_ptr.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/lib/equals_traits.h"
-#include "mojo/public/cpp/bindings/lib/control_message_handler.h"
-#include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
+#include "mojo/public/cpp/bindings/equals_traits.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
-#include "mojo/public/cpp/bindings/lib/union_accessor.h"
-#include "mojo/public/cpp/bindings/native_struct.h"
-#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
#include "mojo/public/cpp/bindings/struct_ptr.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
-#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
#include "mojo/public/cpp/bindings/union_traits.h"
#include "{{module.path}}-shared.h"
{%- for import in imports %}
{%- if variant %}
-#include "{{"%s-%s.h"|format(import.module.path, variant)}}"
+#include "{{"%s-%s.h"|format(import.path, variant)}}"
{%- else %}
-#include "{{import.module.path}}.h"
+#include "{{import.path}}.h"
{%- endif %}
{%- endfor %}
{%- if not for_blink %}
@@ -73,10 +67,30 @@ namespace {{variant}} {
{%- else %}
{# hash_util.h includes template specializations that should be present for
every use of {Inlined}StructPtr. #}
+#include "mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h"
#include "mojo/public/cpp/bindings/lib/wtf_hash_util.h"
-#include "third_party/WebKit/Source/wtf/HashFunctions.h"
-#include "third_party/WebKit/Source/wtf/Optional.h"
-#include "third_party/WebKit/Source/wtf/text/WTFString.h"
+#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
+#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+{%- endif %}
+
+{% if not disallow_interfaces -%}
+#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
+#include "mojo/public/cpp/bindings/associated_interface_request.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/lib/control_message_handler.h"
+#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
+#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
+{%- if for_blink %}
+#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
+{%- endif %}
+{%- endif %}
+
+{% if not disallow_native_types %}
+#include "mojo/public/cpp/bindings/lib/native_enum_serialization.h"
+#include "mojo/public/cpp/bindings/lib/native_struct_serialization.h"
{%- endif %}
{%- for header in extra_public_headers %}
@@ -115,6 +129,9 @@ using {{enum.name}} = {{enum.name}}; // Alias for definition in the parent name
{% for interface in interfaces %}
class {{interface.name}};
using {{interface.name}}Ptr = mojo::InterfacePtr<{{interface.name}}>;
+{%- if for_blink %}
+using Revocable{{interface.name}}Ptr = ::blink::RevocableInterfacePtr<{{interface.name}}>;
+{%- endif %}
using {{interface.name}}PtrInfo = mojo::InterfacePtrInfo<{{interface.name}}>;
using ThreadSafe{{interface.name}}Ptr =
mojo::ThreadSafeInterfacePtr<{{interface.name}}>;
@@ -132,8 +149,8 @@ using {{interface.name}}AssociatedRequest =
{#--- Struct Forward Declarations -#}
{% for struct in structs %}
{%- if struct|is_native_only_kind %}
-using {{struct.name}} = mojo::NativeStruct;
-using {{struct.name}}Ptr = mojo::NativeStructPtr;
+using {{struct.name}} = mojo::native::NativeStruct;
+using {{struct.name}}Ptr = mojo::native::NativeStructPtr;
{%- else %}
class {{struct.name}};
{%- if struct|should_inline %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl
index 96e0d614d8..1d6d82c397 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl
@@ -23,10 +23,10 @@ class {{struct.name}}DataView {
template <typename UserType>
WARN_UNUSED_RESULT bool Read{{name|under_to_camel}}(UserType* output) {
{%- if pf.min_version != 0 %}
- auto* pointer = data_->header_.version >= {{pf.min_version}}
+ auto* pointer = data_->header_.version >= {{pf.min_version}} && !data_->{{name}}.is_null()
? &data_->{{name}} : nullptr;
{%- else %}
- auto* pointer = &data_->{{name}};
+ auto* pointer = !data_->{{name}}.is_null() ? &data_->{{name}} : nullptr;
{%- endif %}
return mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
pointer, output, context_);
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
index 156f7742c4..5f90c0d74c 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
@@ -1,10 +1,30 @@
{%- set class_name = struct.name ~ "_Data" -%}
-class {{class_name}} {
+class {{export_attribute}} {{class_name}} {
public:
- static {{class_name}}* New(mojo::internal::Buffer* buf) {
- return new (buf->Allocate(sizeof({{class_name}}))) {{class_name}}();
- }
+ class BufferWriter {
+ public:
+ BufferWriter() = default;
+
+ void Allocate(mojo::internal::Buffer* serialization_buffer) {
+ serialization_buffer_ = serialization_buffer;
+ index_ = serialization_buffer_->Allocate(sizeof({{class_name}}));
+ new (data()) {{class_name}}();
+ }
+
+ bool is_null() const { return !serialization_buffer_; }
+ {{class_name}}* data() {
+ DCHECK(!is_null());
+ return serialization_buffer_->Get<{{class_name}}>(index_);
+ }
+ {{class_name}}* operator->() { return data(); }
+
+ private:
+ mojo::internal::Buffer* serialization_buffer_ = nullptr;
+ size_t index_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(BufferWriter);
+ };
static bool Validate(const void* data,
mojo::internal::ValidationContext* validation_context);
@@ -38,8 +58,7 @@ class {{class_name}} {
{%- endif %}
private:
- {{class_name}}() : header_({sizeof(*this), {{struct.versions[-1].version}}}) {
- }
+ {{class_name}}();
~{{class_name}}() = delete;
};
static_assert(sizeof({{class_name}}) == {{struct.versions[-1].num_bytes}},
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
index 60dca4010e..1638962050 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
@@ -61,10 +61,12 @@ bool {{class_name}}::Validate(
return true;
{%- endif %}
{%- set field_expr = "object->" ~ packed_field.field.name %}
-{{validation_macros.validate_field(packed_field.field, field_expr, struct.name, true)}}
+{{validation_macros.validate_field(packed_field.field, loop.index, field_expr, struct.name, true)}}
{%- endif %}
{%- endfor %}
return true;
}
+{{class_name}}::{{class_name}}()
+ : header_({sizeof(*this), {{struct.versions[-1].version}}}) {}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
index bb5fb9c496..7c6b9cdd1f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
@@ -1,46 +1,5 @@
{# TODO(yzshen): Make these templates more readable. #}
-{# Computes the serialized size for the specified struct.
- |struct| is the struct definition.
- |input_field_pattern| should be a pattern that contains one string
- placeholder, for example, "input->%s", "p_%s". The placeholder will be
- substituted with struct field names to refer to the input fields.
- |context| is the name of the serialization context.
- |input_may_be_temp| indicates whether any input may be temporary obejcts.
- We need to assign temporary objects to local variables before passing it to
- Serializer, because it is illegal to pass temporary objects as non-const
- references.
- This macro is expanded to compute seriailized size for both:
- - user-defined structs: the input is an instance of the corresponding struct
- wrapper class.
- - method parameters/response parameters: the input is a list of
- arguments.
- It declares |size| of type size_t to store the resulting size. #}
-{%- macro get_serialized_size(struct, input_field_pattern, context,
- input_may_be_temp=False) -%}
- size_t size = sizeof({{struct|get_qualified_name_for_kind(internal=True)}});
-{%- for pf in struct.packed.packed_fields_in_ordinal_order
- if pf.field.kind|is_object_kind or pf.field.kind|is_associated_kind %}
-{%- set name = pf.field.name -%}
-{%- set kind = pf.field.kind -%}
-{%- set original_input_field = input_field_pattern|format(name) %}
-{%- set input_field = "in_%s"|format(name) if input_may_be_temp
- else original_input_field %}
-{%- if input_may_be_temp %}
- decltype({{original_input_field}}) in_{{name}} = {{original_input_field}};
-{%- endif %}
-
-{%- set serializer_type = kind|unmapped_type_for_serializer %}
-{%- if kind|is_union_kind %}
- size += mojo::internal::PrepareToSerialize<{{serializer_type}}>(
- {{input_field}}, true, {{context}});
-{%- else %}
- size += mojo::internal::PrepareToSerialize<{{serializer_type}}>(
- {{input_field}}, {{context}});
-{%- endif %}
-{%- endfor %}
-{%- endmacro -%}
-
{# Serializes the specified struct.
|struct| is the struct definition.
|struct_display_name| is the display name for the struct that can be showed
@@ -48,7 +7,7 @@
|input_field_pattern| should be a pattern that contains one string
placeholder, for example, "input->%s", "p_%s". The placeholder will be
substituted with struct field names to refer to the input fields.
- |output| is the name of the output struct instance.
+ |writer| is the name of the BufferWriter to use for allocation and writing.
|buffer| is the name of the Buffer instance used.
|context| is the name of the serialization context.
|input_may_be_temp|: please see the comments of get_serialized_size.
@@ -57,11 +16,9 @@
wrapper class.
- method parameters/response parameters: the input is a list of
arguments. #}
-{%- macro serialize(struct, struct_display_name, input_field_pattern, output,
+{%- macro serialize(struct, struct_display_name, input_field_pattern, writer,
buffer, context, input_may_be_temp=False) -%}
- auto {{output}} =
- {{struct|get_qualified_name_for_kind(internal=True)}}::New({{buffer}});
- ALLOW_UNUSED_LOCAL({{output}});
+ {{writer}}.Allocate({{buffer}});
{%- for pf in struct.packed.packed_fields_in_ordinal_order %}
{%- set input_field = input_field_pattern|format(pf.field.name) %}
{%- set name = pf.field.name %}
@@ -79,36 +36,41 @@
{%- if kind|is_object_kind %}
{%- if kind|is_array_kind or kind|is_map_kind %}
- typename decltype({{output}}->{{name}})::BaseType* {{name}}_ptr;
+ typename decltype({{writer}}->{{name}})::BaseType::BufferWriter
+ {{name}}_writer;
const mojo::internal::ContainerValidateParams {{name}}_validate_params(
{{kind|get_container_validate_params_ctor_args|indent(10)}});
mojo::internal::Serialize<{{serializer_type}}>(
- {{input_field}}, {{buffer}}, &{{name}}_ptr, &{{name}}_validate_params,
+ {{input_field}}, {{buffer}}, &{{name}}_writer, &{{name}}_validate_params,
{{context}});
- {{output}}->{{name}}.Set({{name}}_ptr);
+ {{writer}}->{{name}}.Set(
+ {{name}}_writer.is_null() ? nullptr : {{name}}_writer.data());
{%- elif kind|is_union_kind %}
- auto {{name}}_ptr = &{{output}}->{{name}};
+ typename decltype({{writer}}->{{name}})::BufferWriter {{name}}_writer;
+ {{name}}_writer.AllocateInline({{buffer}}, &{{writer}}->{{name}});
mojo::internal::Serialize<{{serializer_type}}>(
- {{input_field}}, {{buffer}}, &{{name}}_ptr, true, {{context}});
+ {{input_field}}, {{buffer}}, &{{name}}_writer, true, {{context}});
{%- else %}
- typename decltype({{output}}->{{name}})::BaseType* {{name}}_ptr;
+ typename decltype({{writer}}->{{name}})::BaseType::BufferWriter
+ {{name}}_writer;
mojo::internal::Serialize<{{serializer_type}}>(
- {{input_field}}, {{buffer}}, &{{name}}_ptr, {{context}});
- {{output}}->{{name}}.Set({{name}}_ptr);
+ {{input_field}}, {{buffer}}, &{{name}}_writer, {{context}});
+ {{writer}}->{{name}}.Set(
+ {{name}}_writer.is_null() ? nullptr : {{name}}_writer.data());
{%- endif %}
{%- if not kind|is_nullable_kind %}
MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
- {{output}}->{{name}}.is_null(),
+ {{writer}}->{{name}}.is_null(),
mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
"null {{name}} in {{struct_display_name}}");
{%- endif %}
{%- elif kind|is_any_handle_or_interface_kind %}
mojo::internal::Serialize<{{serializer_type}}>(
- {{input_field}}, &{{output}}->{{name}}, {{context}});
+ {{input_field}}, &{{writer}}->{{name}}, {{context}});
{%- if not kind|is_nullable_kind %}
MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
- !mojo::internal::IsHandleOrInterfaceValid({{output}}->{{name}}),
+ !mojo::internal::IsHandleOrInterfaceValid({{writer}}->{{name}}),
{%- if kind|is_associated_kind %}
mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID,
{%- else %}
@@ -119,10 +81,10 @@
{%- elif kind|is_enum_kind %}
mojo::internal::Serialize<{{serializer_type}}>(
- {{input_field}}, &{{output}}->{{name}});
+ {{input_field}}, &{{writer}}->{{name}});
{%- else %}
- {{output}}->{{name}} = {{input_field}};
+ {{writer}}->{{name}} = {{input_field}};
{%- endif %}
{%- endfor %}
{%- endmacro -%}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
index 835178beda..5571e8449f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
@@ -2,6 +2,8 @@
{%- set data_view = struct|get_qualified_name_for_kind ~ "DataView" %}
{%- set data_type = struct|get_qualified_name_for_kind(internal=True) %}
+{%- if not struct|use_custom_serializer %}
+
namespace internal {
template <typename MaybeConstUserType>
@@ -9,37 +11,17 @@ struct Serializer<{{data_view}}, MaybeConstUserType> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Traits = StructTraits<{{data_view}}, UserType>;
- static size_t PrepareToSerialize(MaybeConstUserType& input,
- SerializationContext* context) {
- if (CallIsNullIfExists<Traits>(input))
- return 0;
-
- void* custom_context = CustomContextHelper<Traits>::SetUp(input, context);
- ALLOW_UNUSED_LOCAL(custom_context);
-
- {{struct_macros.get_serialized_size(
- struct, "CallWithContext(Traits::%s, input, custom_context)",
- "context", True)|indent(2)}}
- return size;
- }
-
static void Serialize(MaybeConstUserType& input,
Buffer* buffer,
- {{data_type}}** output,
+ {{data_type}}::BufferWriter* output,
SerializationContext* context) {
- if (CallIsNullIfExists<Traits>(input)) {
- *output = nullptr;
+ if (CallIsNullIfExists<Traits>(input))
return;
- }
-
- void* custom_context = CustomContextHelper<Traits>::GetNext(context);
-
+ void* custom_context = CustomContextHelper<Traits>::SetUp(input, context);
{{struct_macros.serialize(
struct, struct.name ~ " struct",
- "CallWithContext(Traits::%s, input, custom_context)", "result",
+ "CallWithContext(Traits::%s, input, custom_context)", "(*output)",
"buffer", "context", True)|indent(2)}}
- *output = result;
-
CustomContextHelper<Traits>::TearDown(input, custom_context);
}
@@ -55,3 +37,5 @@ struct Serializer<{{data_view}}, MaybeConstUserType> {
};
} // namespace internal
+
+{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_unserialized_message_context.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_unserialized_message_context.tmpl
new file mode 100644
index 0000000000..2ee085d570
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_unserialized_message_context.tmpl
@@ -0,0 +1,33 @@
+// Used by {{struct.name}}::WrapAsMessage to lazily serialize the struct.
+template <typename UserType, typename DataView>
+struct {{struct.name}}_UnserializedMessageContext
+ : public mojo::internal::UnserializedMessageContext {
+ public:
+ static const mojo::internal::UnserializedMessageContext::Tag kMessageTag;
+
+ {{struct.name}}_UnserializedMessageContext(
+ uint32_t message_name,
+ uint32_t message_flags,
+ UserType input)
+ : mojo::internal::UnserializedMessageContext(&kMessageTag, message_name, message_flags)
+ , user_data_(std::move(input)) {}
+ ~{{struct.name}}_UnserializedMessageContext() override = default;
+
+ UserType TakeData() {
+ return std::move(user_data_);
+ }
+
+ private:
+ // mojo::internal::UnserializedMessageContext:
+ void Serialize(mojo::internal::SerializationContext* context,
+ mojo::internal::Buffer* buffer) override {
+ {{struct.name}}_Data::BufferWriter writer;
+ mojo::internal::Serialize<DataView>(user_data_, buffer, &writer, context);
+ }
+
+ UserType user_data_;
+};
+
+template <typename UserType, typename DataView>
+const mojo::internal::UnserializedMessageContext::Tag
+ {{struct.name}}_UnserializedMessageContext<UserType, DataView>::kMessageTag = {};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl
index 005ba76b61..e14169a263 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl
@@ -2,7 +2,7 @@
{%- set enum_name = union.name ~ "_Tag" -%}
{%- import "struct_macros.tmpl" as struct_macros %}
-class {{class_name}} {
+class {{export_attribute}} {{class_name}} {
public:
// Used to identify Mojom Union Data Classes.
typedef void MojomUnionDataType;
@@ -12,9 +12,38 @@ class {{class_name}} {
// non-inlined union.
~{{class_name}}() {}
- static {{class_name}}* New(mojo::internal::Buffer* buf) {
- return new (buf->Allocate(sizeof({{class_name}}))) {{class_name}}();
- }
+ class BufferWriter {
+ public:
+ BufferWriter() = default;
+
+ void Allocate(mojo::internal::Buffer* serialization_buffer) {
+ serialization_buffer_ = serialization_buffer;
+ index_ = serialization_buffer_->Allocate(sizeof({{class_name}}));
+ new (data()) {{class_name}}();
+ }
+
+ void AllocateInline(mojo::internal::Buffer* serialization_buffer,
+ void* ptr) {
+ const char* start = static_cast<const char*>(
+ serialization_buffer->data());
+ const char* slot = static_cast<const char*>(ptr);
+ DCHECK_GT(slot, start);
+ serialization_buffer_ = serialization_buffer;
+ index_ = slot - start;
+ new (data()) {{class_name}}();
+ }
+
+ bool is_null() const { return !serialization_buffer_; }
+ {{class_name}}* data() {
+ DCHECK(!is_null());
+ return serialization_buffer_->Get<{{class_name}}>(index_);
+ }
+ {{class_name}}* operator->() { return data(); }
+
+ private:
+ mojo::internal::Buffer* serialization_buffer_ = nullptr;
+ size_t index_ = 0;
+ };
static bool Validate(const void* data,
mojo::internal::ValidationContext* validation_context,
@@ -38,6 +67,8 @@ class {{class_name}} {
// "Each non-static data member is allocated as if it were the sole member of
// a struct." - Section 9.5.2 ISO/IEC 14882:2011 (The C++ Spec)
union MOJO_ALIGNAS(8) Union_ {
+ Union_() : unknown(0) {}
+
{%- for field in union.fields %}
{%- if field.kind.spec == 'b' %}
uint8_t f_{{field.name}} : 1;
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl
index af5ea9f8a8..feff2298f0 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl
@@ -32,7 +32,7 @@ bool {{class_name}}::Validate(
{% for field in union.fields %}
case {{enum_name}}::{{field.name|upper}}: {
{%- set field_expr = "object->data.f_" ~ field.name %}
-{{validation_macros.validate_field(field, field_expr, union.name, false)|indent(4)}}
+{{validation_macros.validate_field(field, loop.index, field_expr, union.name, false)|indent(4)}}
return true;
}
{%- endfor %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
index b589ae9147..4e39774b60 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
@@ -8,61 +8,22 @@ struct Serializer<{{data_view}}, MaybeConstUserType> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Traits = UnionTraits<{{data_view}}, UserType>;
- static size_t PrepareToSerialize(MaybeConstUserType& input,
- bool inlined,
- SerializationContext* context) {
- size_t size = inlined ? 0 : sizeof({{data_type}});
-
- if (CallIsNullIfExists<Traits>(input))
- return size;
-
- void* custom_context = CustomContextHelper<Traits>::SetUp(input, context);
- ALLOW_UNUSED_LOCAL(custom_context);
-
- switch (CallWithContext(Traits::GetTag, input, custom_context)) {
-{%- for field in union.fields %}
-{%- set name = field.name %}
- case {{data_view}}::Tag::{{name|upper}}: {
-{%- if field.kind|is_object_kind or field.kind|is_associated_kind %}
-{%- set kind = field.kind %}
-{%- set serializer_type = kind|unmapped_type_for_serializer %}
- decltype(CallWithContext(Traits::{{name}}, input, custom_context))
- in_{{name}} = CallWithContext(Traits::{{name}}, input,
- custom_context);
-{%- if kind|is_union_kind %}
- size += mojo::internal::PrepareToSerialize<{{serializer_type}}>(
- in_{{name}}, false, context);
-{%- else %}
- size += mojo::internal::PrepareToSerialize<{{serializer_type}}>(
- in_{{name}}, context);
-{%- endif %}
-{%- endif %}
- break;
- }
-{%- endfor %}
- }
- return size;
- }
-
static void Serialize(MaybeConstUserType& input,
Buffer* buffer,
- {{data_type}}** output,
+ {{data_type}}::BufferWriter* writer,
bool inlined,
SerializationContext* context) {
if (CallIsNullIfExists<Traits>(input)) {
- if (inlined)
- (*output)->set_null();
- else
- *output = nullptr;
+ if (inlined)
+ writer->data()->set_null();
return;
}
-
- void* custom_context = CustomContextHelper<Traits>::GetNext(context);
+ void* custom_context = CustomContextHelper<Traits>::SetUp(input, context);
if (!inlined)
- *output = {{data_type}}::New(buffer);
+ writer->Allocate(buffer);
- {{data_type}}* result = *output;
+ {{data_type}}::BufferWriter& result = *writer;
ALLOW_UNUSED_LOCAL(result);
// TODO(azani): Handle unknown and objects.
// Set the not-null flag.
@@ -78,25 +39,29 @@ struct Serializer<{{data_view}}, MaybeConstUserType> {
in_{{name}} = CallWithContext(Traits::{{name}}, input,
custom_context);
{%- if kind|is_object_kind %}
- typename decltype(result->data.f_{{name}})::BaseType* ptr;
+ typename decltype(result->data.f_{{name}})::BaseType::BufferWriter
+ value_writer;
{%- if kind|is_union_kind %}
mojo::internal::Serialize<{{serializer_type}}>(
- in_{{name}}, buffer, &ptr, false, context);
+ in_{{name}}, buffer, &value_writer, false, context);
{%- elif kind|is_array_kind or kind|is_map_kind %}
const ContainerValidateParams {{name}}_validate_params(
{{kind|get_container_validate_params_ctor_args|indent(16)}});
mojo::internal::Serialize<{{serializer_type}}>(
- in_{{name}}, buffer, &ptr, &{{name}}_validate_params, context);
-{%- else %}
+ in_{{name}}, buffer, &value_writer, &{{name}}_validate_params,
+ context);
+ {%- else %}
mojo::internal::Serialize<{{serializer_type}}>(
- in_{{name}}, buffer, &ptr, context);
+ in_{{name}}, buffer, &value_writer, context);
{%- endif %}
- result->data.f_{{name}}.Set(ptr);
{%- if not kind|is_nullable_kind %}
MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
- !ptr, mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+ value_writer.is_null(),
+ mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
"null {{name}} in {{union.name}} union");
{%- endif %}
+ result->data.f_{{name}}.Set(
+ value_writer.is_null() ? nullptr : value_writer.data());
{%- elif kind|is_any_handle_or_interface_kind %}
mojo::internal::Serialize<{{serializer_type}}>(
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_traits_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_traits_definition.tmpl
index cde3f95669..f402142460 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_traits_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_traits_definition.tmpl
@@ -4,38 +4,38 @@
bool UnionTraits<{{mojom_type}}::DataView, {{mojom_type}}Ptr>::Read(
{{mojom_type}}::DataView input,
{{mojom_type}}Ptr* output) {
- *output = {{mojom_type}}::New();
- {{mojom_type}}Ptr& result = *output;
+ using UnionType = {{mojom_type}};
+ using Tag = UnionType::Tag;
- internal::UnionAccessor<{{mojom_type}}> result_acc(result.get());
switch (input.tag()) {
{%- for field in union.fields %}
- case {{mojom_type}}::Tag::{{field.name|upper}}: {
+ case Tag::{{field.name|upper}}: {
{%- set name = field.name %}
{%- set kind = field.kind %}
{%- set serializer_type = kind|unmapped_type_for_serializer %}
{%- if kind|is_object_kind %}
- result_acc.SwitchActive({{mojom_type}}::Tag::{{name|upper}});
- if (!input.Read{{name|under_to_camel}}(result_acc.data()->{{name}}))
+ {{kind|cpp_wrapper_type(True)}} result_{{name}};
+ if (!input.Read{{name|under_to_camel}}(&result_{{name}}))
return false;
+ *output = UnionType::New{{field.name|under_to_camel}}(
+ std::move(result_{{name}}));
{%- elif kind|is_any_handle_kind %}
- auto result_{{name}} = input.Take{{name|under_to_camel}}();
- result->set_{{name}}(std::move(result_{{name}}));
+ *output = UnionType::New{{field.name|under_to_camel}}(
+ input.Take{{name|under_to_camel}}());
{%- elif kind|is_any_interface_kind %}
- auto result_{{name}} =
- input.Take{{name|under_to_camel}}<typename std::remove_reference<decltype(result->get_{{name}}())>::type>();
- result->set_{{name}}(std::move(result_{{name}}));
+ *output = UnionType::New{{field.name|under_to_camel}}(
+ input.Take{{name|under_to_camel}}<{{kind|cpp_wrapper_type(True)}}>());
{%- elif kind|is_enum_kind %}
- decltype(result->get_{{name}}()) result_{{name}};
+ {{kind|cpp_wrapper_type(True)}} result_{{name}};
if (!input.Read{{name|under_to_camel}}(&result_{{name}}))
return false;
- result->set_{{name}}(result_{{name}});
+ *output = UnionType::New{{field.name|under_to_camel}}(result_{{name}});
{%- else %}
- result->set_{{name}}(input.{{name}}());
+ *output = UnionType::New{{field.name|under_to_camel}}(input.{{name}}());
{%- endif %}
break;
}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl
index a50a585c09..457f2f9977 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl
@@ -2,20 +2,18 @@
(struct/array/string/map/union). If it is a union, |union_is_inlined|
indicates whether the union is inlined. (Nested unions are not inlined.)
This macro is expanded by the Validate() method. #}
-{%- macro validate_object(field, field_expr, object_name, union_is_inlined) %}
+{%- macro validate_object(field, field_index, field_expr, union_is_inlined) %}
{%- set name = field.name %}
{%- set kind = field.kind %}
{%- if not kind|is_nullable_kind %}
{%- if kind|is_union_kind and union_is_inlined %}
if (!mojo::internal::ValidateInlinedUnionNonNullable(
- {{field_expr}}, "null {{name}} field in {{object_name}}",
- validation_context)) {
+ {{field_expr}}, {{field_index}}, validation_context)) {
return false;
}
{%- else %}
if (!mojo::internal::ValidatePointerNonNullable(
- {{field_expr}}, "null {{name}} field in {{object_name}}",
- validation_context)) {
+ {{field_expr}}, {{field_index}}, validation_context)) {
return false;
}
{%- endif %}
@@ -47,13 +45,12 @@
{#- Validates the specified field, which is supposed to be a handle,
an interface, an associated interface or an associated interface request.
This macro is expanded by the Validate() method. #}
-{%- macro validate_handle_or_interface(field, field_expr, object_name) %}
+{%- macro validate_handle_or_interface(field, field_index, field_expr, object_name) %}
{%- set name = field.name %}
{%- set kind = field.kind %}
{%- if not kind|is_nullable_kind %}
if (!mojo::internal::ValidateHandleOrInterfaceNonNullable(
- {{field_expr}},
- "invalid {{name}} field in {{object_name}}", validation_context)) {
+ {{field_expr}}, {{field_index}}, validation_context)) {
return false;
}
{%- endif %}
@@ -71,11 +68,11 @@
return false;
{%- endmacro %}
-{%- macro validate_field(field, field_expr, object_name, union_is_inlined) %}
+{%- macro validate_field(field, field_index, field_expr, object_name, union_is_inlined) %}
{%- if field.kind|is_object_kind -%}
-{{validate_object(field, field_expr, object_name, union_is_inlined)}}
+{{validate_object(field, field_index, field_expr, union_is_inlined)}}
{%- elif field.kind|is_any_handle_or_interface_kind -%}
-{{validate_handle_or_interface(field, field_expr, object_name)}}
+{{validate_handle_or_interface(field, field_index, field_expr, object_name)}}
{%- elif field.kind|is_enum_kind %}
{{validate_enum(field, field_expr)}}
{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
index 7ad9b4e1bc..e03fd0cb3e 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
@@ -16,8 +16,7 @@ class {{export_attribute}} {{struct.name}} {
template <typename... Args>
static {{struct.name}}Ptr New(Args&&... args) {
return {{struct.name}}Ptr(
- base::in_place,
- std::forward<Args>(args)...);
+ base::in_place, std::forward<Args>(args)...);
}
template <typename U>
@@ -33,7 +32,7 @@ class {{export_attribute}} {{struct.name}} {
{% for constructor in struct|struct_constructors %}
{% if constructor.params|length == 1 %}explicit {% endif %}{{struct.name}}(
{%- for field in constructor.params %}
-{%- set type = field.kind|cpp_wrapper_param_type %}
+{%- set type = field.kind|cpp_wrapper_param_type_new %}
{%- set name = field.name %}
{{type}} {{name}}
{%- if not loop.last -%},{%- endif %}
@@ -64,16 +63,56 @@ class {{export_attribute}} {{struct.name}} {
template <typename UserType>
static {{serialization_result_type}} Serialize(UserType* input) {
- return mojo::internal::StructSerializeImpl<
+ return mojo::internal::SerializeImpl<
{{struct.name}}::DataView, {{serialization_result_type}}>(input);
}
template <typename UserType>
+ static mojo::Message SerializeAsMessage(UserType* input) {
+ return mojo::internal::SerializeAsMessageImpl<
+ {{struct.name}}::DataView>(input);
+ }
+
+ // The returned Message is serialized only if the message is moved
+ // cross-process or cross-language. Otherwise if the message is Deserialized
+ // as the same UserType |input| will just be moved to |output| in
+ // DeserializeFromMessage.
+ template <typename UserType>
+ static mojo::Message WrapAsMessage(UserType input) {
+ return mojo::Message(std::make_unique<
+ internal::{{struct.name}}_UnserializedMessageContext<
+ UserType, {{struct.name}}::DataView>>(0, 0, std::move(input)));
+ }
+
+ template <typename UserType>
+ static bool Deserialize(const void* data,
+ size_t data_num_bytes,
+ UserType* output) {
+ return mojo::internal::DeserializeImpl<{{struct.name}}::DataView>(
+ data, data_num_bytes, std::vector<mojo::ScopedHandle>(), output, Validate);
+ }
+
+ template <typename UserType>
static bool Deserialize(const {{serialization_result_type}}& input,
UserType* output) {
- return mojo::internal::StructDeserializeImpl<
- {{struct.name}}::DataView, {{serialization_result_type}}>(
- input, output, Validate);
+ return {{struct.name}}::Deserialize(
+ input.size() == 0 ? nullptr : &input.front(), input.size(), output);
+ }
+
+ template <typename UserType>
+ static bool DeserializeFromMessage(mojo::Message input,
+ UserType* output) {
+ auto context = input.TakeUnserializedContext<
+ internal::{{struct.name}}_UnserializedMessageContext<
+ UserType, {{struct.name}}::DataView>>();
+ if (context) {
+ *output = std::move(context->TakeData());
+ return true;
+ }
+ input.SerializeIfNecessary();
+ return mojo::internal::DeserializeImpl<{{struct.name}}::DataView>(
+ input.payload(), input.payload_num_bytes(),
+ std::move(*input.mutable_handles()), output, Validate);
}
{#--- Struct members #}
@@ -91,4 +130,3 @@ class {{export_attribute}} {{struct.name}} {
DISALLOW_COPY_AND_ASSIGN({{struct.name}});
{%- endif %}
};
-
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
index ab8c22d49c..d65dd69137 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
@@ -1,7 +1,7 @@
{% for constructor in struct|struct_constructors %}
{{struct.name}}::{{struct.name}}(
{%- for field in constructor.params %}
-{%- set type = field.kind|cpp_wrapper_param_type %}
+{%- set type = field.kind|cpp_wrapper_param_type_new %}
{%- set name = field.name %}
{{type}} {{name}}_in
{%- if not loop.last -%},{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl
index feb861569f..fab27cd8d0 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl
@@ -11,9 +11,9 @@ template <typename StructPtrType>
template <typename T,
typename std::enable_if<std::is_same<
T, {{struct.name}}>::value>::type*>
-bool {{struct.name}}::Equals(const T& other) const {
+bool {{struct.name}}::Equals(const T& other_struct) const {
{%- for field in struct.fields %}
- if (!mojo::internal::Equals(this->{{field.name}}, other.{{field.name}}))
+ if (!mojo::Equals(this->{{field.name}}, other_struct.{{field.name}}))
return false;
{%- endfor %}
return true;
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl
index 8b7cf9e6b1..a0be109b03 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl
@@ -4,7 +4,20 @@ class {{export_attribute}} {{union.name}} {
using Data_ = internal::{{union.name}}_Data;
using Tag = Data_::{{union.name}}_Tag;
- static {{union.name}}Ptr New();
+ static {{union.name}}Ptr New() {
+ return {{union.name}}Ptr(base::in_place);
+ }
+
+{%- for field in union.fields %}
+ // Construct an instance holding |{{field.name}}|.
+ static {{union.name}}Ptr
+ New{{field.name|under_to_camel}}(
+ {{field.kind|cpp_wrapper_param_type_new}} {{field.name}}) {
+ auto result = {{union.name}}Ptr(base::in_place);
+ result->set_{{field.name}}(std::move({{field.name}}));
+ return result;
+ }
+{%- endfor %}
template <typename U>
static {{union.name}}Ptr From(const U& u) {
@@ -54,11 +67,25 @@ class {{export_attribute}} {{union.name}} {
{%- endif %}
}
- void set_{{field.name}}({{field.kind|cpp_wrapper_param_type}} {{field.name}});
+ void set_{{field.name}}(
+ {{field.kind|cpp_wrapper_param_type_new}} {{field.name}});
{%- endfor %}
+ template <typename UserType>
+ static mojo::Message SerializeAsMessage(UserType* input) {
+ return mojo::internal::SerializeAsMessageImpl<
+ {{union.name}}::DataView>(input);
+ }
+
+ template <typename UserType>
+ static bool DeserializeFromMessage(mojo::Message input,
+ UserType* output) {
+ return mojo::internal::DeserializeImpl<{{union.name}}::DataView>(
+ input.payload(), input.payload_num_bytes(),
+ std::move(*input.mutable_handles()), output, Validate);
+ }
+
private:
- friend class mojo::internal::UnionAccessor<{{union.name}}>;
union Union_ {
Union_() {}
~Union_() {}
@@ -72,8 +99,10 @@ class {{export_attribute}} {{union.name}} {
{%- endif %}
{%- endfor %}
};
- void SwitchActive(Tag new_active);
- void SetActive(Tag new_active);
+
+ static bool Validate(const void* data,
+ mojo::internal::ValidationContext* validation_context);
+
void DestroyActive();
Tag tag_;
Union_ data_;
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl
index b9e416a9f4..5f9bde51d2 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl
@@ -1,12 +1,11 @@
-// static
-{{union.name}}Ptr {{union.name}}::New() {
- return {{union.name}}Ptr(base::in_place);
-}
-
-{{union.name}}::{{union.name}}() {
- // TODO(azani): Implement default values here when/if we support them.
- // TODO(azani): Set to UNKNOWN when unknown is implemented.
- SetActive(static_cast<Tag>(0));
+{%- set default_field = union.fields.0 %}
+{{union.name}}::{{union.name}}() : tag_(Tag::{{default_field.name|upper}}) {
+{%- if default_field.kind|is_object_kind or
+ default_field.kind|is_any_handle_or_interface_kind %}
+ data_.{{default_field.name}} = new {{default_field.kind|cpp_wrapper_type}};
+{%- else %}
+ data_.{{default_field.name}} = {{default_field.kind|cpp_wrapper_type}}();
+{%- endif %}
}
{{union.name}}::~{{union.name}}() {
@@ -14,43 +13,28 @@
}
{% for field in union.fields %}
-void {{union.name}}::set_{{field.name}}({{field.kind|cpp_wrapper_param_type}} {{field.name}}) {
- SwitchActive(Tag::{{field.name|upper}});
-{% if field.kind|is_string_kind %}
- *(data_.{{field.name}}) = {{field.name}};
-{% elif field.kind|is_object_kind or
+void {{union.name}}::set_{{field.name}}(
+ {{field.kind|cpp_wrapper_param_type_new}} {{field.name}}) {
+{%- if field.kind|is_object_kind or
field.kind|is_any_handle_or_interface_kind %}
- *(data_.{{field.name}}) = std::move({{field.name}});
+ if (tag_ == Tag::{{field.name|upper}}) {
+ *(data_.{{field.name}}) = std::move({{field.name}});
+ } else {
+ DestroyActive();
+ tag_ = Tag::{{field.name|upper}};
+ data_.{{field.name}} = new {{field.kind|cpp_wrapper_type}}(
+ std::move({{field.name}}));
+ }
{%- else %}
+ if (tag_ != Tag::{{field.name|upper}}) {
+ DestroyActive();
+ tag_ = Tag::{{field.name|upper}};
+ }
data_.{{field.name}} = {{field.name}};
{%- endif %}
}
{%- endfor %}
-void {{union.name}}::SwitchActive(Tag new_active) {
- if (new_active == tag_) {
- return;
- }
-
- DestroyActive();
- SetActive(new_active);
-}
-
-void {{union.name}}::SetActive(Tag new_active) {
- switch (new_active) {
-{% for field in union.fields %}
- case Tag::{{field.name|upper}}:
-{% if field.kind|is_object_kind or
- field.kind|is_any_handle_or_interface_kind %}
- data_.{{field.name}} = new {{field.kind|cpp_wrapper_type}}();
-{%- endif %}
- break;
-{%- endfor %}
- }
-
- tag_ = new_active;
-}
-
void {{union.name}}::DestroyActive() {
switch (tag_) {
{% for field in union.fields %}
@@ -81,5 +65,10 @@ size_t {{union.name}}::Hash(size_t seed) const {
return seed;
}
}
-
{%- endif %}
+
+bool {{union.name}}::Validate(
+ const void* data,
+ mojo::internal::ValidationContext* validation_context) {
+ return Data_::Validate(data, validation_context, false);
+}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_template_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_template_definition.tmpl
index 4c4851fa83..a29a1b7f55 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_template_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_template_definition.tmpl
@@ -30,9 +30,9 @@ bool {{union.name}}::Equals(const T& other) const {
case Tag::{{field.name|upper}}:
{%- if field.kind|is_object_kind or
field.kind|is_any_handle_or_interface_kind %}
- return mojo::internal::Equals(*(data_.{{field.name}}), *(other.data_.{{field.name}}));
+ return mojo::Equals(*(data_.{{field.name}}), *(other.data_.{{field.name}}));
{%- else %}
- return mojo::internal::Equals(data_.{{field.name}}, other.data_.{{field.name}});
+ return mojo::Equals(data_.{{field.name}}, other.data_.{{field.name}});
{%- endif %}
{%- endfor %}
};
diff --git a/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl
index 4c0823cce6..7af57bd968 100644
--- a/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl
@@ -1,34 +1,6 @@
{%- from "constant_definition.tmpl" import constant_def %}
{%- from "enum_definition.tmpl" import enum_def %}
-{%- macro equality(kind, v1, v2, ne=False) -%}
-{%- if kind|is_reference_kind -%}
-{%- if kind|is_array_kind -%}
-{%- if kind.kind|is_reference_kind -%}
-{%- if ne %}!{%- endif %}java.util.Arrays.deepEquals({{v1}}, {{v2}})
-{%- else -%}
-{%- if ne %}!{%- endif %}java.util.Arrays.equals({{v1}}, {{v2}})
-{%- endif -%}
-{%- else -%}
-{%- if ne %}!{%- endif %}org.chromium.mojo.bindings.BindingsHelper.equals({{v1}}, {{v2}})
-{%- endif -%}
-{%- else -%}
-{{v1}} {%- if ne %}!={%- else %}=={%- endif %} {{v2}}
-{%- endif -%}
-{%- endmacro -%}
-
-{%- macro hash(kind, v) -%}
-{%- if kind|is_array_kind -%}
-{%- if kind.kind|is_reference_kind -%}
-java.util.Arrays.deepHashCode({{v}})
-{%- else -%}
-java.util.Arrays.hashCode({{v}})
-{%- endif -%}
-{%- else -%}
-org.chromium.mojo.bindings.BindingsHelper.hashCode({{v}})
-{%- endif -%}
-{%- endmacro -%}
-
{%- macro array_element_size(kind) -%}
{%- if kind|is_union_kind %}
org.chromium.mojo.bindings.BindingsHelper.UNION_SIZE
@@ -167,9 +139,9 @@ if ({{variable}} != null) {
super(STRUCT_SIZE, version);
{%- for field in struct.fields %}
{%- if field.default %}
- {{field|name}} = {{field|default_value}};
+ this.{{field|name}} = {{field|default_value}};
{%- elif field.kind|is_any_handle_kind %}
- {{field|name}} = org.chromium.mojo.system.InvalidHandle.INSTANCE;
+ this.{{field|name}} = org.chromium.mojo.system.InvalidHandle.INSTANCE;
{%- endif %}
{%- endfor %}
}
@@ -188,9 +160,6 @@ if ({{variable}} != null) {
* @throws org.chromium.mojo.bindings.DeserializationException on deserialization failure.
*/
public static {{struct|name}} deserialize(java.nio.ByteBuffer data) {
- if (data == null)
- return null;
-
return deserialize(new org.chromium.mojo.bindings.Message(
data, new java.util.ArrayList<org.chromium.mojo.system.Handle>()));
}
@@ -204,14 +173,30 @@ if ({{variable}} != null) {
{{struct|name}} result;
try {
org.chromium.mojo.bindings.DataHeader mainDataHeader = decoder0.readAndValidateDataHeader(VERSION_ARRAY);
- result = new {{struct|name}}(mainDataHeader.elementsOrVersion);
+ final int elementsOrVersion = mainDataHeader.elementsOrVersion;
+ result = new {{struct|name}}(elementsOrVersion);
+
+{%- set prev_ver = [0] %}
{%- for byte in struct.bytes %}
{%- for packed_field in byte.packed_fields %}
- if (mainDataHeader.elementsOrVersion >= {{packed_field.min_version}}) {
- {{decode('result.' ~ packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(16)}}
+{%- if packed_field.min_version != prev_ver[-1] %}
+{%- if prev_ver[-1] != 0 %}
}
+{%- endif %}
+{%- set _ = prev_ver.append(packed_field.min_version) %}
+{%- if prev_ver[-1] != 0 %}
+ if (elementsOrVersion >= {{packed_field.min_version}}) {
+{%- endif %}
+{%- endif %}
+ {
+ {{decode('result.' ~ packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(16)}}
+ }
{%- endfor %}
{%- endfor %}
+{%- if prev_ver[-1] != 0 %}
+ }
+{%- endif %}
+
} finally {
decoder0.decreaseStackDepth();
}
@@ -228,43 +213,9 @@ if ({{variable}} != null) {
{%- endif %}
{%- for byte in struct.bytes %}
{%- for packed_field in byte.packed_fields %}
- {{encode(packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(8)}}
-{%- endfor %}
-{%- endfor %}
- }
-
- /**
- * @see Object#equals(Object)
- */
- @Override
- public boolean equals(Object object) {
- if (object == this)
- return true;
- if (object == null)
- return false;
- if (getClass() != object.getClass())
- return false;
-{%- if struct.fields|length %}
- {{struct|name}} other = ({{struct|name}}) object;
-{%- for field in struct.fields %}
- if ({{equality(field.kind, 'this.'~field|name, 'other.'~field|name, True)}})
- return false;
+ {{encode('this.' ~ packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(8)}}
{%- endfor %}
-{%- endif %}
- return true;
- }
-
- /**
- * @see Object#hashCode()
- */
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = prime + getClass().hashCode();
-{%- for field in struct.fields %}
- result = prime * result + {{hash(field.kind, field|name)}};
{%- endfor %}
- return result;
}
}
{%- endmacro %}
@@ -279,34 +230,20 @@ public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
{%- endfor %}
};
- private int mTag_ = -1;
{%- for field in union.fields %}
private {{field.kind|java_type}} m{{field|ucc}};
{%- endfor %}
- public int which() {
- return mTag_;
- }
-
- public boolean isUnknown() {
- return mTag_ == -1;
- }
{%- for field in union.fields %}
- // TODO(rockot): Fix the findbugs error and remove this suppression.
- // See http://crbug.com/570386.
- @SuppressFBWarnings("EI_EXPOSE_REP2")
public void set{{field|ucc}}({{field.kind|java_type}} {{field|name}}) {
- mTag_ = Tag.{{field|ucc}};
- m{{field|ucc}} = {{field|name}};
+ this.mTag = Tag.{{field|ucc}};
+ this.m{{field|ucc}} = {{field|name}};
}
- // TODO(rockot): Fix the findbugs error and remove this suppression.
- // See http://crbug.com/570386.
- @SuppressFBWarnings("EI_EXPOSE_REP")
public {{field.kind|java_type}} get{{field|ucc}}() {
- assert mTag_ == Tag.{{field|ucc}};
- return m{{field|ucc}};
+ assert this.mTag == Tag.{{field|ucc}};
+ return this.m{{field|ucc}};
}
{%- endfor %}
@@ -314,18 +251,19 @@ public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
@Override
protected final void encode(org.chromium.mojo.bindings.Encoder encoder0, int offset) {
encoder0.encode(org.chromium.mojo.bindings.BindingsHelper.UNION_SIZE, offset);
- encoder0.encode(mTag_, offset + 4);
- switch (mTag_) {
+ encoder0.encode(this.mTag, offset + 4);
+ switch (mTag) {
{%- for field in union.fields %}
case Tag.{{field|ucc}}: {
{%- if field.kind|is_union_kind %}
- if (m{{field|ucc}} == null) {
+ if (this.m{{field|ucc}} == null) {
encoder0.encodeNullPointer(offset + 8, {{field.kind|is_nullable_kind|java_true_false}});
} else {
- m{{field|ucc}}.encode(encoder0.encoderForUnionPointer(offset + 8), 0);
+ encoder0.encoderForUnionPointer(offset + 8).encode(
+ this.m{{field|ucc}}, 0, {{field.kind|is_nullable_kind|java_true_false}});
}
{%- else %}
- {{encode('m' ~ field|ucc, field.kind, 'offset + 8', 0)|indent(16)}}
+ {{encode('this.m' ~ field|ucc, field.kind, 'offset + 8', 0)|indent(16)}}
{%- endif %}
break;
}
@@ -352,59 +290,12 @@ public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
{%- if field.kind|is_union_kind %}
org.chromium.mojo.bindings.Decoder decoder1 = decoder0.readPointer(offset + org.chromium.mojo.bindings.DataHeader.HEADER_SIZE, {{field.kind|is_nullable_kind|java_true_false}});
if (decoder1 != null) {
- result.m{{field|ucc}} = {{field.kind|name}}.decode(decoder1, 0);
+ result.m{{field|ucc}} = {{field.kind|java_type}}.decode(decoder1, 0);
}
{%- else %}
{{decode('result.m'~field|ucc, field.kind, 'offset + org.chromium.mojo.bindings.DataHeader.HEADER_SIZE', 0)|indent(16)}}
{%- endif %}
- result.mTag_ = Tag.{{field|ucc}};
- break;
- }
-{%- endfor %}
- default: {
- break;
- }
- }
- return result;
- }
-
- /**
- * @see Object#equals(Object)
- */
- @Override
- public boolean equals(Object object) {
- if (object == this)
- return true;
- if (object == null)
- return false;
- if (getClass() != object.getClass())
- return false;
- {{union|name}} other = ({{union|name}}) object;
- if (mTag_ != other.mTag_)
- return false;
- switch (mTag_) {
-{%- for field in union.fields %}
- case Tag.{{field|ucc}}:
- return {{equality(field.kind, 'm'~field|ucc, 'other.m'~field|ucc)}};
-{%- endfor %}
- default:
- break;
- }
- return false;
- }
-
- /**
- * @see Object#hashCode()
- */
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = prime + getClass().hashCode();
- result = prime * result + org.chromium.mojo.bindings.BindingsHelper.hashCode(mTag_);
- switch (mTag_) {
-{%- for field in union.fields %}
- case Tag.{{field|ucc}}: {
- result = prime * result + {{hash(field.kind, 'm'~field|ucc)}};
+ result.mTag = Tag.{{field|ucc}};
break;
}
{%- endfor %}
diff --git a/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl b/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl
index 1d67890452..410bfce997 100644
--- a/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl
+++ b/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl
@@ -10,5 +10,4 @@
package {{package}};
-import org.chromium.base.annotations.SuppressFBWarnings;
-import org.chromium.mojo.bindings.DeserializationException; \ No newline at end of file
+import org.chromium.mojo.bindings.DeserializationException;
diff --git a/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
index c7dcbbc7cb..27e9a3a08d 100644
--- a/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
@@ -58,23 +58,28 @@ org.chromium.mojo.bindings.MessageHeader.MESSAGE_IS_RESPONSE_FLAG
public static final {{manager_class(interface, True)}} MANAGER =
new {{manager_class(interface, True)}}() {
+ @Override
public String getName() {
- return "{{namespace|replace(".","::")}}::{{interface.name}}";
+ return "{{namespace}}.{{interface.name}}";
}
+ @Override
public int getVersion() {
return {{interface.version}};
}
+ @Override
public Proxy buildProxy(org.chromium.mojo.system.Core core,
org.chromium.mojo.bindings.MessageReceiverWithResponder messageReceiver) {
return new Proxy(core, messageReceiver);
}
+ @Override
public Stub buildStub(org.chromium.mojo.system.Core core, {{interface|name}} impl) {
return new Stub(core, impl);
}
+ @Override
public {{interface|name}}[] buildArray(int size) {
return new {{interface|name}}[size];
}
diff --git a/mojo/public/tools/bindings/generators/js_templates/externs/interface_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/externs/interface_definition.tmpl
new file mode 100644
index 0000000000..672b5d5d89
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/js_templates/externs/interface_definition.tmpl
@@ -0,0 +1,34 @@
+{% macro generateInterfaceClass() -%}
+class {
+{%- for method in interface.methods %}
+ /**
+{%- for parameter in method.parameters %}
+ * @param { {{parameter.kind|closure_type_with_nullability}} } {{parameter.name|sanitize_identifier}}
+{%- endfor -%}
+{%- if method.response_parameters != None %}
+ * @return {Promise}
+{%- endif %}
+ */
+ {{method.name}}(
+{%- for parameter in method.parameters -%}
+{{parameter.name|sanitize_identifier}}{% if not loop.last %}, {% endif %}
+{%- endfor -%}
+) {}
+{%- endfor %}
+};
+{%- endmacro %}
+
+/**
+ * @const
+ * @type { !mojo.Interface };
+ */
+{{module.namespace}}.{{interface.name}};
+
+/** @interface */
+{{module.namespace}}.{{interface.name}}Impl = {{ generateInterfaceClass() }}
+
+/**
+ * @implements { mojo.InterfacePtr }
+ * @implements { {{module.namespace}}.{{interface.name}}Impl }
+ */
+{{module.namespace}}.{{interface.name}}Ptr = {{ generateInterfaceClass() }}
diff --git a/mojo/public/tools/bindings/generators/js_templates/externs/module.externs.tmpl b/mojo/public/tools/bindings/generators/js_templates/externs/module.externs.tmpl
new file mode 100644
index 0000000000..fd711068f2
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/js_templates/externs/module.externs.tmpl
@@ -0,0 +1,37 @@
+// Copyright 2018 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.
+
+{% for declaration in module.namespace|namespace_declarations -%}
+/** @const */
+{%- if loop.first %}
+var {{declaration}} = {};
+{% else %}
+{{declaration}} = {};
+{% endif -%}
+{%- endfor -%}
+
+{#--- Constant definitions #}
+{%- for constant in module.constants %}
+/** @type { {{constant.kind|closure_type_with_nullability }} } */
+{{module.namespace}}.{{constant.name}};
+{%- endfor %}
+
+{#--- Enum definitions #}
+{% for enum in enums %}
+/** @enum {number} */
+{{module.namespace}}.{{enum.name}} = {};
+{%- for field in enum.fields %}
+{{module.namespace}}.{{enum.name}}.{{field.name}};
+{%- endfor %}
+{%- endfor %}
+
+{#--- Interface definitions #}
+{%- for interface in interfaces -%}
+{%- include "externs/interface_definition.tmpl" %}
+{% endfor -%}
+
+{#--- Struct definitions #}
+{%- for struct in structs -%}
+{%- include "externs/struct_definition.tmpl" %}
+{% endfor -%}
diff --git a/mojo/public/tools/bindings/generators/js_templates/externs/struct_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/externs/struct_definition.tmpl
new file mode 100644
index 0000000000..4aecb67c84
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/js_templates/externs/struct_definition.tmpl
@@ -0,0 +1,8 @@
+{{module.namespace}}.{{struct.name}} = class {
+ constructor() {
+{%- for packed_field in struct.packed.packed_fields %}
+ /** @type { {{packed_field.field.kind|closure_type_with_nullability}} } */
+ this.{{packed_field.field.name}};
+{%- endfor %}
+ }
+};
diff --git a/mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl b/mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl
new file mode 100644
index 0000000000..a91260ed9a
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl
@@ -0,0 +1,125 @@
+{%- macro get_handle_deps(kind, name) -%}
+{%- if kind|is_struct_kind or kind|is_union_kind -%}
+{{name}}.getHandleDeps()
+{%- elif kind|is_array_kind -%}
+[].concat.apply([], {{name}}.map(function(val) {
+ if (val) {
+ return {{get_handle_deps(kind.kind, 'val')|indent(4)}};
+ }
+ return [];
+}))
+{%- elif kind|is_map_kind -%}
+[].concat.apply([], Array.from({{name}}.values()).map(function(val) {
+ if (val) {
+ return {{get_handle_deps(kind.value_kind, 'val')|indent(4)}};
+ }
+ return [];
+}))
+{%- elif kind|is_any_handle_or_interface_kind -%}
+ ["{{kind|fuzz_handle_name}}"]
+{%- else -%}
+ []
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro set_handles(kind, name) -%}
+{%- if kind|is_struct_kind or kind|is_union_kind -%}
+idx = {{name}}.setHandlesInternal_(handles, idx)
+{%- elif kind|is_array_kind -%}
+{{name}}.forEach(function(val) {
+ {{set_handles(kind.kind, 'val')|indent(2)}};
+})
+{%- elif kind|is_map_kind -%}
+{{name}}.forEach(function(val) {
+ {{set_handles(kind.value_kind, 'val')|indent(2)}};
+})
+{%- elif kind|is_any_handle_or_interface_kind -%}
+{{name}} = handles[idx++];
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro build_call(obj, operation, type, name) -%}
+{%- if name -%}
+{{obj}}.{{operation}}{{type}}({{((name,) + varargs)|join(', ')}})
+{%- else -%}
+{{obj}}.{{operation}}{{type}}({{varargs|join(', ')}})
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate_enum(obj, operation, kind, name) -%}
+{%- if kind.max_value is not none -%}
+{{build_call(obj, operation, 'Enum', name, '0', kind.max_value)}}
+{%- else -%}
+{{build_call(obj, operation, 'Enum', name)}}
+{%- endif %}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate_array(obj, operation, kind, name) -%}
+{%- if operation == 'mutate' -%}
+{{obj}}.{{operation}}Array({{name}}, function(val) {
+ return {{generate_or_mutate(obj, operation, kind.kind, 'val')|indent(2)}};
+})
+{%- else -%}
+{{obj}}.{{operation}}Array(function() {
+ return {{generate_or_mutate(obj, operation, kind.kind)|indent(2)}};
+})
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate_map(obj, operation, kind, name) -%}
+{%- if operation == 'mutate' -%}
+{{obj}}.{{operation}}Map({{name}},
+ function(val) {
+ return {{generate_or_mutate(obj, operation, kind.key_kind, 'val')|indent(4)}};
+ },
+ function(val) {
+ return {{generate_or_mutate(obj, operation, kind.value_kind, 'val')|indent(4)}};
+ })
+{%- else -%}
+{{obj}}.{{operation}}Map(
+ function() {
+ return {{generate_or_mutate(obj, operation, kind.key_kind)|indent(4)}};
+ },
+ function() {
+ return {{generate_or_mutate(obj, operation, kind.value_kind)|indent(4)}};
+ })
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate_primitive(obj, operation, kind, name) -%}
+{%- if kind|is_reference_kind -%}
+{{build_call(obj, operation, kind|primitive_to_fuzz_type, name, kind.is_nullable|to_js_boolean)}}
+{%- else -%}
+{{build_call(obj, operation, kind|primitive_to_fuzz_type, name)}}
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate_interface(obj, operation, kind, name) -%}
+{%- if kind|is_interface_request_kind -%}
+{{build_call(obj, operation, 'InterfaceRequest', name, '"' ~ kind.kind.module.namespace ~ '.' ~ kind.kind.name ~ '"', kind.is_nullable|to_js_boolean)}}
+{%- elif kind|is_interface_kind -%}
+{{build_call(obj, operation, 'Interface', name, '"' ~ kind.module.namespace ~ '.' ~ kind.name ~ '"', kind.is_nullable|to_js_boolean)}}
+{%- elif kind|is_associated_interface_request_kind -%}
+{{build_call(obj, operation, 'AssociatedInterfaceRequest', name, '"' ~ kind.kind.module.namespace ~ '.' ~ kind.kind.name ~ '"', kind.is_nullable|to_js_boolean)}}
+{%- elif kind|is_associated_interface_kind -%}
+{{build_call(obj, operation, 'AssociatedInterface', name, '"' ~ kind.kind.module.namespace ~ '.' ~ kind.kind.name ~ '"', kind.is_nullable|to_js_boolean)}}
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate(obj, operation, kind, name='') -%}
+{%- if kind|is_primitive_kind -%}
+{{generate_or_mutate_primitive(obj, operation, kind, name)}}
+{%- elif kind|is_any_interface_kind -%}
+{{generate_or_mutate_interface(obj, operation, kind, name)}}
+{%- elif kind|is_enum_kind -%}
+{{generate_or_mutate_enum(obj, operation, kind, name)}}
+{%- elif kind|is_struct_kind -%}
+{{build_call(obj, operation, 'Struct', name, kind.module.namespace ~ '.' ~ kind.name, kind.is_nullable|to_js_boolean)}}
+{%- elif kind|is_union_kind -%}
+{{build_call(obj, operation, 'Union', name, kind.module.namespace ~ '.' ~ kind.name, kind.is_nullable|to_js_boolean)}}
+{%- elif kind|is_array_kind -%}
+{{generate_or_mutate_array(obj, operation, kind, name)}}
+{%- elif kind|is_map_kind -%}
+{{generate_or_mutate_map(obj, operation, kind, name)}}
+{%- endif -%}
+{%- endmacro -%}
diff --git a/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
index 11e319c1f7..d6b29007ac 100644
--- a/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
@@ -1,5 +1,7 @@
{%- for method in interface.methods %}
- var k{{interface.name}}_{{method.name}}_Name = {{method.ordinal}};
+{%- set interface_method_id =
+ interface.mojom_name ~ "_" ~ method.mojom_name %}
+ var k{{interface_method_id}}_Name = {{method.ordinal}};
{%- endfor %}
function {{interface.name}}Ptr(handleOrPtrInfo) {
@@ -7,45 +9,72 @@
handleOrPtrInfo);
}
+ function {{interface.name}}AssociatedPtr(associatedInterfacePtrInfo) {
+ this.ptr = new associatedBindings.AssociatedInterfacePtrController(
+ {{interface.name}}, associatedInterfacePtrInfo);
+ }
+
+ {{interface.name}}AssociatedPtr.prototype =
+ Object.create({{interface.name}}Ptr.prototype);
+ {{interface.name}}AssociatedPtr.prototype.constructor =
+ {{interface.name}}AssociatedPtr;
+
function {{interface.name}}Proxy(receiver) {
this.receiver_ = receiver;
}
{%- for method in interface.methods %}
- {{interface.name}}Ptr.prototype.{{method.name|stylize_method}} = function() {
- return {{interface.name}}Proxy.prototype.{{method.name|stylize_method}}
+{%- set interface_method_id =
+ interface.mojom_name ~ "_" ~ method.mojom_name %}
+ {{interface.name}}Ptr.prototype.{{method.name}} = function() {
+ return {{interface.name}}Proxy.prototype.{{method.name}}
.apply(this.ptr.getProxy(), arguments);
};
- {{interface.name}}Proxy.prototype.{{method.name|stylize_method}} = function(
+ {{interface.name}}Proxy.prototype.{{method.name}} = function(
{%- for parameter in method.parameters -%}
-{{parameter.name}}{% if not loop.last %}, {% endif %}
+{{parameter.name|sanitize_identifier}}{% if not loop.last %}, {% endif %}
{%- endfor -%}
) {
- var params = new {{interface.name}}_{{method.name}}_Params();
+ var params_ = new {{interface_method_id}}_Params();
{%- for parameter in method.parameters %}
- params.{{parameter.name}} = {{parameter.name}};
+ params_.{{parameter.name}} = {{parameter.name|sanitize_identifier}};
{%- endfor %}
{%- if method.response_parameters == None %}
- 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);
+{%- if method|method_passes_associated_kinds %}
+ var builder = new codec.MessageV2Builder(
+ k{{interface_method_id}}_Name,
+ codec.align({{interface_method_id}}_Params.encodedSize));
+ builder.setPayload({{interface_method_id}}_Params, params_);
+{%- else %}
+ var builder = new codec.MessageV0Builder(
+ k{{interface_method_id}}_Name,
+ codec.align({{interface_method_id}}_Params.encodedSize));
+ builder.encodeStruct({{interface_method_id}}_Params, params_);
+{%- endif %}
var message = builder.finish();
this.receiver_.accept(message);
{%- else %}
return new Promise(function(resolve, reject) {
- var builder = new codec.MessageWithRequestIDBuilder(
- k{{interface.name}}_{{method.name}}_Name,
- codec.align({{interface.name}}_{{method.name}}_Params.encodedSize),
+{%- if method|method_passes_associated_kinds %}
+ var builder = new codec.MessageV2Builder(
+ k{{interface_method_id}}_Name,
+ codec.align({{interface_method_id}}_Params.encodedSize),
codec.kMessageExpectsResponse, 0);
- builder.encodeStruct({{interface.name}}_{{method.name}}_Params, params);
+ builder.setPayload({{interface_method_id}}_Params, params_);
+{%- else %}
+ var builder = new codec.MessageV1Builder(
+ k{{interface_method_id}}_Name,
+ codec.align({{interface_method_id}}_Params.encodedSize),
+ codec.kMessageExpectsResponse, 0);
+ builder.encodeStruct({{interface_method_id}}_Params, params_);
+{%- endif %}
var message = builder.finish();
this.receiver_.acceptAndExpectResponse(message).then(function(message) {
var reader = new codec.MessageReader(message);
var responseParams =
- reader.decodeStruct({{interface.name}}_{{method.name}}_ResponseParams);
+ reader.decodeStruct({{interface_method_id}}_ResponseParams);
resolve(responseParams);
}).catch(function(result) {
reject(Error("Connection error: " + result));
@@ -60,9 +89,8 @@
}
{%- for method in interface.methods %}
-{%- set js_method_name = method.name|stylize_method %}
- {{interface.name}}Stub.prototype.{{js_method_name}} = function({{method.parameters|map(attribute='name')|join(', ')}}) {
- return this.delegate_ && this.delegate_.{{js_method_name}} && this.delegate_.{{js_method_name}}({{method.parameters|map(attribute='name')|join(', ')}});
+ {{interface.name}}Stub.prototype.{{method.name}} = function({{method.parameters|map(attribute='name')|map('sanitize_identifier')|join(', ')}}) {
+ return this.delegate_ && this.delegate_.{{method.name}} && this.delegate_.{{method.name}}({{method.parameters|map(attribute='name')|map('sanitize_identifier')|join(', ')}});
}
{%- endfor %}
@@ -70,10 +98,12 @@
var reader = new codec.MessageReader(message);
switch (reader.messageName) {
{%- for method in interface.methods %}
+{%- set interface_method_id =
+ interface.mojom_name ~ "_" ~ method.mojom_name %}
{%- if method.response_parameters == None %}
- case k{{interface.name}}_{{method.name}}_Name:
- var params = reader.decodeStruct({{interface.name}}_{{method.name}}_Params);
- this.{{method.name|stylize_method}}(
+ case k{{interface_method_id}}_Name:
+ var params = reader.decodeStruct({{interface_method_id}}_Params);
+ this.{{method.name}}(
{%- for parameter in method.parameters -%}
params.{{parameter.name}}{% if not loop.last %}, {% endif %}
{%- endfor %});
@@ -90,24 +120,36 @@
var reader = new codec.MessageReader(message);
switch (reader.messageName) {
{%- for method in interface.methods %}
+{%- set interface_method_id =
+ interface.mojom_name ~ "_" ~ method.mojom_name %}
{%- if method.response_parameters != None %}
- case k{{interface.name}}_{{method.name}}_Name:
- var params = reader.decodeStruct({{interface.name}}_{{method.name}}_Params);
- this.{{method.name|stylize_method}}(
+ case k{{interface_method_id}}_Name:
+ var params = reader.decodeStruct({{interface_method_id}}_Params);
+ this.{{method.name}}(
{%- for parameter in method.parameters -%}
params.{{parameter.name}}{% if not loop.last %}, {% endif -%}
{%- endfor %}).then(function(response) {
var responseParams =
- new {{interface.name}}_{{method.name}}_ResponseParams();
+ new {{interface_method_id}}_ResponseParams();
{%- for parameter in method.response_parameters %}
responseParams.{{parameter.name}} = response.{{parameter.name}};
{%- endfor %}
- var builder = new codec.MessageWithRequestIDBuilder(
- k{{interface.name}}_{{method.name}}_Name,
- codec.align({{interface.name}}_{{method.name}}_ResponseParams.encodedSize),
+{%- if method|method_passes_associated_kinds %}
+ var builder = new codec.MessageV2Builder(
+ k{{interface_method_id}}_Name,
+ codec.align({{interface_method_id}}_ResponseParams
+ .encodedSize),
codec.kMessageIsResponse, reader.requestID);
- builder.encodeStruct({{interface.name}}_{{method.name}}_ResponseParams,
+ builder.setPayload({{interface_method_id}}_ResponseParams,
responseParams);
+{%- else %}
+ var builder = new codec.MessageV1Builder(
+ k{{interface_method_id}}_Name,
+ codec.align({{interface_method_id}}_ResponseParams.encodedSize),
+ codec.kMessageIsResponse, reader.requestID);
+ builder.encodeStruct({{interface_method_id}}_ResponseParams,
+ responseParams);
+{%- endif %}
var message = builder.finish();
responder.accept(message);
});
@@ -129,13 +171,15 @@ params.{{parameter.name}}{% if not loop.last %}, {% endif -%}
var paramsClass = null;
switch (message.getName()) {
{%- for method in interface.methods %}
- case k{{interface.name}}_{{method.name}}_Name:
+{%- set interface_method_id =
+ interface.mojom_name ~ "_" ~ method.mojom_name %}
+ case k{{interface_method_id}}_Name:
{%- if method.response_parameters == None %}
if (!message.expectsResponse() && !message.isResponse())
- paramsClass = {{interface.name}}_{{method.name}}_Params;
+ paramsClass = {{interface_method_id}}_Params;
{%- else %}
if (message.expectsResponse())
- paramsClass = {{interface.name}}_{{method.name}}_Params;
+ paramsClass = {{interface_method_id}}_Params;
{%- endif %}
break;
{%- endfor %}
@@ -154,10 +198,12 @@ params.{{parameter.name}}{% if not loop.last %}, {% endif -%}
var paramsClass = null;
switch (message.getName()) {
{%- for method in interface.methods %}
+{%- set interface_method_id =
+ interface.mojom_name ~ "_" ~ method.mojom_name %}
{%- if method.response_parameters != None %}
- case k{{interface.name}}_{{method.name}}_Name:
+ case k{{interface_method_id}}_Name:
if (message.isResponse())
- paramsClass = {{interface.name}}_{{method.name}}_ResponseParams;
+ paramsClass = {{interface_method_id}}_ResponseParams;
break;
{%- endif %}
{%- endfor %}
@@ -169,7 +215,7 @@ params.{{parameter.name}}{% if not loop.last %}, {% endif -%}
}
var {{interface.name}} = {
- name: '{{namespace|replace(".","::")}}::{{interface.name}}',
+ name: '{{module.mojom_namespace}}.{{interface.mojom_name}}',
kVersion: {{interface.version}},
ptrClass: {{interface.name}}Ptr,
proxyClass: {{interface.name}}Proxy,
@@ -180,6 +226,18 @@ params.{{parameter.name}}{% if not loop.last %}, {% endif -%}
{%- else %}
validateResponse: null,
{%- endif %}
+{%- if generate_fuzzing %}
+ mojomId: '{{module.path}}',
+ fuzzMethods: {
+ {%- for method in interface.methods %}
+ {%- set interface_method_id =
+ interface.mojom_name ~ "_" ~ method.mojom_name %}
+ {{ method.name }}: {
+ params: {{interface_method_id}}_Params,
+ },
+ {%- endfor %}
+ },
+{%- endif %}
};
{#--- Interface Constants #}
{%- for constant in interface.constants %}
diff --git a/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl b/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
index 3637b196ac..6cdacb2d95 100644
--- a/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-{%- if use_new_js_bindings %}
-
'use strict';
(function() {
@@ -14,57 +12,23 @@
}
mojo.internal.markMojomLoaded(mojomId);
- // TODO(yzshen): Define these aliases to minimize the differences between the
- // old/new modes. Remove them when the old mode goes away.
+{#- TODO(crbug.com/795977): Change the media router extension to not mess with
+ the mojo namespace, so that we can refer to mojo directly. #}
var bindings = mojo;
+ var associatedBindings = mojo;
var codec = mojo.internal;
var validator = mojo.internal;
-{%- for import in imports %}
+ var exports = mojo.internal.exposeNamespace('{{module.namespace}}');
+
+{%- for import in imports %}
var {{import.unique_name}} =
- mojo.internal.exposeNamespace('{{import.module.namespace}}');
+ mojo.internal.exposeNamespace('{{import.namespace}}');
if (mojo.config.autoLoadMojomDeps) {
mojo.internal.loadMojomIfNecessary(
- '{{import.module.path}}',
- new URL(
- '{{import.module|get_relative_path(module)}}.js',
- document.currentScript.src).href);
+ '{{import.path}}', '{{import|get_relative_url(module)}}.js');
}
-{%- endfor %}
+{%- endfor %}
{% include "module_definition.tmpl" %}
})();
-
-{%- else %}
-
-define("{{module.path}}", [
-{%- if module.path !=
- "mojo/public/interfaces/bindings/interface_control_messages.mojom" and
- module.path !=
- "mojo/public/interfaces/bindings/pipe_control_messages.mojom" %}
- "mojo/public/js/bindings",
-{%- endif %}
- "mojo/public/js/codec",
- "mojo/public/js/core",
- "mojo/public/js/validator",
-{%- for import in imports %}
- "{{import.module.path}}",
-{%- endfor %}
-], function(
-{%- if module.path !=
- "mojo/public/interfaces/bindings/interface_control_messages.mojom" and
- module.path !=
- "mojo/public/interfaces/bindings/pipe_control_messages.mojom" -%}
-bindings, {% endif -%}
-codec, core, validator
-{%- for import in imports -%}
- , {{import.unique_name}}
-{%- endfor -%}
-) {
-
-{%- include "module_definition.tmpl" %}
-
- return exports;
-});
-
-{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl
index a119ee9480..a6736b5658 100644
--- a/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl
@@ -17,7 +17,7 @@
{#--- Union definitions #}
{%- from "union_definition.tmpl" import union_def %}
{%- for union in unions %}
-{{union_def(union)|indent(2)}}
+{{union_def(union, generate_fuzzing)|indent(2)}}
{%- endfor %}
{#--- Interface definitions #}
@@ -25,12 +25,6 @@
{%- include "interface_definition.tmpl" %}
{%- endfor %}
-{%- if use_new_js_bindings %}
- var exports = mojo.internal.exposeNamespace("{{module.namespace}}");
-{%- else %}
- var exports = {};
-{%- endif %}
-
{%- for constant in module.constants %}
exports.{{constant.name}} = {{constant.name}};
{%- endfor %}
@@ -46,4 +40,5 @@
{%- for interface in interfaces %}
exports.{{interface.name}} = {{interface.name}};
exports.{{interface.name}}Ptr = {{interface.name}}Ptr;
+ exports.{{interface.name}}AssociatedPtr = {{interface.name}}AssociatedPtr;
{%- endfor %}
diff --git a/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
index e823e46155..b2ca3eac71 100644
--- a/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
@@ -30,6 +30,54 @@
}
};
+{#--- Fuzzing #}
+{%- if generate_fuzzing %}
+{%- from "fuzzing.tmpl" import generate_or_mutate %}
+ {{struct.name}}.generate = function(generator_) {
+ var generated = new {{struct.name}};
+{%- for field in struct.fields %}
+ generated.{{field.name}} = {{generate_or_mutate('generator_', 'generate', field.kind)|indent(4)}};
+{%- endfor %}
+ return generated;
+ };
+
+ {{struct.name}}.prototype.mutate = function(mutator_) {
+{%- for field in struct.fields %}
+ if (mutator_.chooseMutateField()) {
+ this.{{field.name}} = {{generate_or_mutate('mutator_', 'mutate', field.kind, 'this.' ~ field.name)|indent(6)}};
+ }
+{%- endfor %}
+ return this;
+ };
+
+{%- from "fuzzing.tmpl" import get_handle_deps %}
+ {{struct.name}}.prototype.getHandleDeps = function() {
+ var handles = [];
+{%- for field in struct.fields %}
+{%- if field.kind|contains_handles_or_interfaces %}
+ if (this.{{field.name}} !== null) {
+ Array.prototype.push.apply(handles, {{get_handle_deps(field.kind, 'this.' ~ field.name)|indent(6)}});
+ }
+{%- endif %}
+{%- endfor %}
+ return handles;
+ };
+
+ {{struct.name}}.prototype.setHandles = function() {
+ this.setHandlesInternal_(arguments, 0);
+ };
+
+{%- from "fuzzing.tmpl" import set_handles %}
+ {{struct.name}}.prototype.setHandlesInternal_ = function(handles, idx) {
+{%- for field in struct.fields %}
+{%- if field.kind|contains_handles_or_interfaces %}
+ {{set_handles(field.kind, 'this.' ~ field.name)|indent(4)}};
+{%- endif %}
+{%- endfor %}
+ return idx;
+ };
+{%- endif %}
+
{#--- Validation #}
{{struct.name}}.validate = function(messageValidator, offset) {
@@ -58,8 +106,9 @@
{%- set offset = packed_field|field_offset %}
{%- set field = packed_field.field %}
{%- set name = struct.name ~ '.' ~ field.name %}
-{% if field|is_object_field or field|is_any_handle_or_interface_field or
- field|is_enum_field %}
+{% if field.kind|is_object_kind or
+ field.kind|is_any_handle_or_interface_kind or
+ field.kind|is_enum_kind %}
{% if packed_field.min_version > last_checked_version %}
{% set last_checked_version = packed_field.min_version %}
// version check {{name}}
@@ -84,7 +133,7 @@
var version = decoder.readUint32();
{%- for byte in struct.bytes %}
{%- if byte.packed_fields|length >= 1 and
- byte.packed_fields[0].field|is_bool_field %}
+ byte.packed_fields[0].field.kind|is_bool_kind %}
packed = decoder.readUint8();
{%- for packed_field in byte.packed_fields %}
val.{{packed_field.field.name}} = (packed >> {{packed_field.bit}}) & 1 ? true : false;
@@ -108,7 +157,7 @@
{%- for byte in struct.bytes %}
{%- if byte.packed_fields|length >= 1 and
- byte.packed_fields[0].field|is_bool_field %}
+ byte.packed_fields[0].field.kind|is_bool_kind %}
packed = 0;
{%- for packed_field in byte.packed_fields %}
packed |= (val.{{packed_field.field.name}} & 1) << {{packed_field.bit}}
diff --git a/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl
index 4823febeca..ad857b2c25 100644
--- a/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl
@@ -1,4 +1,4 @@
-{%- macro union_def(union) %}
+{%- macro union_def(union, generate_fuzzing=false) %}
function {{union.name}}(value) {
this.initDefault_();
this.initValue_(value);
@@ -39,6 +39,66 @@ function {{union.name}}(value) {
this[keys[0]] = value[keys[0]];
}
+{%- if generate_fuzzing %}
+{%- from "fuzzing.tmpl" import generate_or_mutate %}
+{{union.name}}.generate = function(generator_) {
+ var generated = new {{union.name}};
+ var generators = [
+{%- for field in union.fields %}
+ {
+ field: "{{field.name}}",
+
+ generator: function() { return {{generate_or_mutate('generator_', 'generate', field.kind)|indent(6)}}; },
+ },
+{%- endfor %}
+ ];
+
+ var result = generator_.generateUnionField(generators);
+ generated[result.field] = result.value;
+ return generated;
+}
+
+{{union.name}}.prototype.mutate = function(mutator_) {
+ var mutators = [
+{%- for field in union.fields %}
+ {
+ field: "{{field.name}}",
+
+ mutator: function(val) { return {{generate_or_mutate('mutator_', 'mutate', field.kind, 'val.' ~ field.name)|indent(6)}}; },
+ },
+{%- endfor %}
+ ];
+
+ var result = mutator_.mutateUnionField(this, mutators);
+ this[result.field] = result.value;
+ return this;
+}
+
+{%- from "fuzzing.tmpl" import get_handle_deps %}
+{{union.name}}.prototype.getHandleDeps = function() {
+{%- for field in union.fields %}
+{%- if field.kind|contains_handles_or_interfaces %}
+ if (this.$tag == {{union.name}}.Tags.{{field.name}}) {
+ return {{get_handle_deps(field.kind, 'this.' ~ field.name)}};
+ }
+{%- endif %}
+{%- endfor %}
+ return [];
+}
+
+{%- from "fuzzing.tmpl" import set_handles %}
+{{union.name}}.prototype.setHandles = function() {
+{%- for field in union.fields %}
+{%- if field.kind|contains_handles_or_interfaces %}
+ if (this.$tag == {{union.name}}.Tags.{{field.name}}) {
+ return {{set_handles(field.kind, 'this.' ~ field.name)}};
+ }
+{%- endif %}
+{%- endfor %}
+ return [];
+}
+{%- endif %}
+
{%- for field in union.fields %}
Object.defineProperty({{union.name}}.prototype, "{{field.name}}", {
get: function() {
@@ -89,7 +149,7 @@ Object.defineProperty({{union.name}}.prototype, "{{field.name}}", {
switch (val.$tag) {
{%- for field in union.fields %}
case {{union.name}}.Tags.{{field.name}}:
-{%- if field|is_bool_field %}
+{%- if field.kind|is_bool_kind %}
encoder.writeUint8(val.{{field.name}} ? 1 : 0);
{%- else %}
encoder.{{field.kind|union_encode_snippet}}val.{{field.name}});
@@ -115,7 +175,7 @@ Object.defineProperty({{union.name}}.prototype, "{{field.name}}", {
switch (tag) {
{%- for field in union.fields %}
case {{union.name}}.Tags.{{field.name}}:
-{%- if field|is_bool_field %}
+{%- if field.kind|is_bool_kind %}
result.{{field.name}} = decoder.readUint8() ? true : false;
{%- else %}
result.{{field.name}} = decoder.{{field.kind|union_decode_snippet}};
diff --git a/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl b/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl
index d4e15a7859..0e9b89315c 100644
--- a/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl
@@ -4,35 +4,43 @@ if (err !== validator.validationError.NONE)
{%- endmacro %}
{%- macro _validate_field(field, offset, name) %}
-{%- if field|is_string_pointer_field %}
+{%- if field.kind|is_string_kind %}
// validate {{name}}
err = messageValidator.validateStringPointer({{offset}}, {{field|validate_nullable_params}})
{{_check_err()}}
-{%- elif field|is_array_pointer_field %}
+{%- elif field.kind|is_array_kind %}
// validate {{name}}
err = messageValidator.validateArrayPointer({{offset}}, {{field|validate_array_params}});
{{_check_err()}}
-{%- elif field|is_struct_pointer_field %}
+{%- elif field.kind|is_struct_kind %}
// validate {{name}}
err = messageValidator.validateStructPointer({{offset}}, {{field|validate_struct_params}});
{{_check_err()}}
-{%- elif field|is_map_pointer_field %}
+{%- elif field.kind|is_map_kind %}
// validate {{name}}
err = messageValidator.validateMapPointer({{offset}}, {{field|validate_map_params}});
{{_check_err()}}
-{%- elif field|is_interface_field %}
+{%- elif field.kind|is_interface_kind %}
// validate {{name}}
err = messageValidator.validateInterface({{offset}}, {{field|validate_nullable_params}});
{{_check_err()}}
-{%- elif field|is_interface_request_field %}
+{%- elif field.kind|is_interface_request_kind %}
// validate {{name}}
err = messageValidator.validateInterfaceRequest({{offset}}, {{field|validate_nullable_params}})
{{_check_err()}}
-{%- elif field|is_handle_field %}
+{%- elif field.kind|is_associated_interface_kind %}
+// validate {{name}}
+err = messageValidator.validateAssociatedInterface({{offset}}, {{field|validate_nullable_params}});
+{{_check_err()}}
+{%- elif field.kind|is_associated_interface_request_kind %}
+// validate {{name}}
+err = messageValidator.validateAssociatedInterfaceRequest({{offset}}, {{field|validate_nullable_params}})
+{{_check_err()}}
+{%- elif field.kind|is_any_handle_kind %}
// validate {{name}}
err = messageValidator.validateHandle({{offset}}, {{field|validate_nullable_params}})
{{_check_err()}}
-{%- elif field|is_enum_field %}
+{%- elif field.kind|is_enum_kind %}
// validate {{name}}
err = messageValidator.validateEnum({{offset}}, {{field|validate_enum_params}});
{{_check_err()}}
@@ -40,17 +48,17 @@ err = messageValidator.validateEnum({{offset}}, {{field|validate_enum_params}});
{%- endmacro %}
{%- macro validate_struct_field(field, offset, name) %}
-{%- if field|is_union_field %}
+{%- if field.kind|is_union_kind %}
// validate {{name}}
err = messageValidator.validateUnion({{offset}}, {{field|validate_union_params}});
{{_check_err()}}
-{%- else %}
+{%- else -%}
{{_validate_field(field, offset, name)}}
{%- endif %}
{%- endmacro %}
{%- macro validate_union_field(field, offset, name) %}
-{%- if field|is_union_field %}
+{%- if field.kind|is_union_kind %}
// validate {{name}}
err = messageValidator.validateNestedUnion({{offset}}, {{field|validate_union_params}});
{{_check_err()}}
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index 38d222b136..ceded69e1f 100644
--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -32,15 +32,6 @@ _kind_to_cpp_literal_suffix = {
mojom.UINT64: "ULL",
}
-# TODO(rockot): Get rid of these globals. This requires some refactoring of the
-# generator library code so that filters can use the generator as context.
-_current_typemap = {}
-_for_blink = False
-# TODO(rockot, yzshen): The variant handling is kind of a hack currently. Make
-# it right.
-_variant = None
-_export_attribute = None
-
class _NameFormatter(object):
"""A formatter for the names of kinds or values."""
@@ -50,7 +41,7 @@ class _NameFormatter(object):
self._variant = variant
def Format(self, separator, prefixed=False, internal=False,
- include_variant=False, add_same_module_namespaces=False,
+ include_variant=False, omit_namespace_for_module=None,
flatten_nested_kind=False):
"""Formats the name according to the given configuration.
@@ -60,15 +51,15 @@ class _NameFormatter(object):
internal: Returns the name in the "internal" namespace.
include_variant: Whether to include variant as namespace. If |internal| is
True, then this flag is ignored and variant is not included.
- add_same_module_namespaces: Includes all namespaces even if the token is
- from the same module as the current mojom file.
+ omit_namespace_for_module: If the token is from the specified module,
+ don't add the namespaces of the module to the name.
flatten_nested_kind: It is allowed to define enums inside structs and
interfaces. If this flag is set to True, this method concatenates the
parent kind and the nested kind with '_', instead of treating the
parent kind as a scope."""
parts = []
- if self._ShouldIncludeNamespace(add_same_module_namespaces):
+ if self._ShouldIncludeNamespace(omit_namespace_for_module):
if prefixed:
parts.append("")
parts.extend(self._GetNamespace())
@@ -77,16 +68,16 @@ class _NameFormatter(object):
parts.extend(self._GetName(internal, flatten_nested_kind))
return separator.join(parts)
- def FormatForCpp(self, add_same_module_namespaces=False, internal=False,
+ def FormatForCpp(self, omit_namespace_for_module=None, internal=False,
flatten_nested_kind=False):
return self.Format(
"::", prefixed=True,
- add_same_module_namespaces=add_same_module_namespaces,
+ omit_namespace_for_module=omit_namespace_for_module,
internal=internal, include_variant=True,
flatten_nested_kind=flatten_nested_kind)
def FormatForMojom(self):
- return self.Format(".", add_same_module_namespaces=True)
+ return self.Format(".")
def _MapKindName(self, token, internal):
if not internal:
@@ -119,105 +110,32 @@ class _NameFormatter(object):
name_parts.append(self._MapKindName(self._token, internal))
return name_parts
- def _ShouldIncludeNamespace(self, add_same_module_namespaces):
- return add_same_module_namespaces or self._token.imported_from
+ def _ShouldIncludeNamespace(self, omit_namespace_for_module):
+ return self._token.module and (
+ not omit_namespace_for_module or
+ self._token.module.path != omit_namespace_for_module.path)
def _GetNamespace(self):
- if self._token.imported_from:
- return NamespaceToArray(self._token.imported_from["namespace"])
- elif hasattr(self._token, "module"):
+ if self._token.module:
return NamespaceToArray(self._token.module.namespace)
- return []
-
-
-def ConstantValue(constant):
- return ExpressionToText(constant.value, kind=constant.kind)
-# TODO(yzshen): Revisit the default value feature. It was designed prior to
-# custom type mapping.
-def DefaultValue(field):
- if field.default:
- if mojom.IsStructKind(field.kind):
- assert field.default == "default"
- if not IsTypemappedKind(field.kind):
- return "%s::New()" % GetNameForKind(field.kind)
- return ExpressionToText(field.default, kind=field.kind)
- return ""
def NamespaceToArray(namespace):
return namespace.split(".") if namespace else []
-def GetNameForKind(kind, internal=False, flatten_nested_kind=False,
- add_same_module_namespaces=False):
- return _NameFormatter(kind, _variant).FormatForCpp(
- internal=internal, flatten_nested_kind=flatten_nested_kind,
- add_same_module_namespaces=add_same_module_namespaces)
-
-def GetQualifiedNameForKind(kind, internal=False, flatten_nested_kind=False,
- include_variant=True):
- return _NameFormatter(
- kind, _variant if include_variant else None).FormatForCpp(
- internal=internal, add_same_module_namespaces=True,
- flatten_nested_kind=flatten_nested_kind)
-
def GetWtfHashFnNameForEnum(enum):
- return _NameFormatter(
- enum, None).Format("_", internal=True, add_same_module_namespaces=True,
- flatten_nested_kind=True) + "HashFn"
-
-
-def GetFullMojomNameForKind(kind):
- return _NameFormatter(kind, _variant).FormatForMojom()
+ return _NameFormatter(enum, None).Format("_", internal=True,
+ flatten_nested_kind=True) + "HashFn"
-def IsTypemappedKind(kind):
- return hasattr(kind, "name") and \
- GetFullMojomNameForKind(kind) in _current_typemap
def IsNativeOnlyKind(kind):
return (mojom.IsStructKind(kind) or mojom.IsEnumKind(kind)) and \
kind.native_only
-def IsHashableKind(kind):
- """Check if the kind can be hashed.
-
- Args:
- kind: {Kind} The kind to check.
-
- Returns:
- {bool} True if a value of this kind can be hashed.
- """
- checked = set()
- def Check(kind):
- if kind.spec in checked:
- return True
- checked.add(kind.spec)
- if mojom.IsNullableKind(kind):
- return False
- elif mojom.IsStructKind(kind):
- if (IsTypemappedKind(kind) and
- not _current_typemap[GetFullMojomNameForKind(kind)]["hashable"]):
- return False
- return all(Check(field.kind) for field in kind.fields)
- elif mojom.IsEnumKind(kind):
- return not IsTypemappedKind(kind) or _current_typemap[
- GetFullMojomNameForKind(kind)]["hashable"]
- elif mojom.IsUnionKind(kind):
- return all(Check(field.kind) for field in kind.fields)
- elif mojom.IsAnyHandleKind(kind):
- return False
- elif mojom.IsAnyInterfaceKind(kind):
- return False
- # TODO(tibell): Arrays and maps could be made hashable. We just don't have a
- # use case yet.
- elif mojom.IsArrayKind(kind):
- return False
- elif mojom.IsMapKind(kind):
- return False
- else:
- return True
- return Check(kind)
+def UseCustomSerializer(kind):
+ return mojom.IsStructKind(kind) and kind.custom_serializer
def AllEnumValues(enum):
@@ -232,252 +150,9 @@ def AllEnumValues(enum):
return set(field.numeric_value for field in enum.fields)
-def GetNativeTypeName(typemapped_kind):
- return _current_typemap[GetFullMojomNameForKind(typemapped_kind)]["typename"]
-
def GetCppPodType(kind):
return _kind_to_cpp_type[kind]
-def FormatConstantDeclaration(constant, nested=False):
- if mojom.IsStringKind(constant.kind):
- if nested:
- return "const char %s[]" % constant.name
- return "%sextern const char %s[]" % \
- ((_export_attribute + " ") if _export_attribute else "", constant.name)
- return "constexpr %s %s = %s" % (GetCppPodType(constant.kind), constant.name,
- ConstantValue(constant))
-
-def GetCppWrapperType(kind, add_same_module_namespaces=False):
- def _AddOptional(type_name):
- pattern = "WTF::Optional<%s>" if _for_blink else "base::Optional<%s>"
- return pattern % type_name
-
- if IsTypemappedKind(kind):
- type_name = GetNativeTypeName(kind)
- if (mojom.IsNullableKind(kind) and
- not _current_typemap[GetFullMojomNameForKind(kind)][
- "nullable_is_same_type"]):
- type_name = _AddOptional(type_name)
- return type_name
- if mojom.IsEnumKind(kind):
- return GetNameForKind(
- kind, add_same_module_namespaces=add_same_module_namespaces)
- if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
- return "%sPtr" % GetNameForKind(
- kind, add_same_module_namespaces=add_same_module_namespaces)
- if mojom.IsArrayKind(kind):
- pattern = "WTF::Vector<%s>" if _for_blink else "std::vector<%s>"
- if mojom.IsNullableKind(kind):
- pattern = _AddOptional(pattern)
- return pattern % GetCppWrapperType(
- kind.kind, add_same_module_namespaces=add_same_module_namespaces)
- if mojom.IsMapKind(kind):
- pattern = ("WTF::HashMap<%s, %s>" if _for_blink else
- "std::unordered_map<%s, %s>")
- if mojom.IsNullableKind(kind):
- pattern = _AddOptional(pattern)
- return pattern % (
- GetCppWrapperType(
- kind.key_kind,
- add_same_module_namespaces=add_same_module_namespaces),
- GetCppWrapperType(
- kind.value_kind,
- add_same_module_namespaces=add_same_module_namespaces))
- if mojom.IsInterfaceKind(kind):
- return "%sPtr" % GetNameForKind(
- kind, add_same_module_namespaces=add_same_module_namespaces)
- if mojom.IsInterfaceRequestKind(kind):
- return "%sRequest" % GetNameForKind(
- kind.kind, add_same_module_namespaces=add_same_module_namespaces)
- if mojom.IsAssociatedInterfaceKind(kind):
- return "%sAssociatedPtrInfo" % GetNameForKind(
- kind.kind, add_same_module_namespaces=add_same_module_namespaces)
- if mojom.IsAssociatedInterfaceRequestKind(kind):
- return "%sAssociatedRequest" % GetNameForKind(
- kind.kind, add_same_module_namespaces=add_same_module_namespaces)
- if mojom.IsStringKind(kind):
- if _for_blink:
- return "WTF::String"
- type_name = "std::string"
- return _AddOptional(type_name) if mojom.IsNullableKind(kind) else type_name
- if mojom.IsGenericHandleKind(kind):
- return "mojo::ScopedHandle"
- if mojom.IsDataPipeConsumerKind(kind):
- return "mojo::ScopedDataPipeConsumerHandle"
- if mojom.IsDataPipeProducerKind(kind):
- return "mojo::ScopedDataPipeProducerHandle"
- if mojom.IsMessagePipeKind(kind):
- return "mojo::ScopedMessagePipeHandle"
- if mojom.IsSharedBufferKind(kind):
- return "mojo::ScopedSharedBufferHandle"
- if not kind in _kind_to_cpp_type:
- raise Exception("Unrecognized kind %s" % kind.spec)
- return _kind_to_cpp_type[kind]
-
-def IsMoveOnlyKind(kind):
- if IsTypemappedKind(kind):
- if mojom.IsEnumKind(kind):
- return False
- return _current_typemap[GetFullMojomNameForKind(kind)]["move_only"]
- if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
- return True
- if mojom.IsArrayKind(kind):
- return IsMoveOnlyKind(kind.kind)
- if mojom.IsMapKind(kind):
- return IsMoveOnlyKind(kind.value_kind)
- if mojom.IsAnyHandleOrInterfaceKind(kind):
- return True
- return False
-
-def IsCopyablePassByValue(kind):
- if not IsTypemappedKind(kind):
- return False
- return _current_typemap[GetFullMojomNameForKind(kind)][
- "copyable_pass_by_value"]
-
-def ShouldPassParamByValue(kind):
- return ((not mojom.IsReferenceKind(kind)) or IsMoveOnlyKind(kind) or
- IsCopyablePassByValue(kind))
-
-def GetCppWrapperParamType(kind):
- cpp_wrapper_type = GetCppWrapperType(kind)
- return (cpp_wrapper_type if ShouldPassParamByValue(kind)
- else "const %s&" % cpp_wrapper_type)
-
-def GetCppFieldType(kind):
- if mojom.IsStructKind(kind):
- return ("mojo::internal::Pointer<%s>" %
- GetNameForKind(kind, internal=True))
- if mojom.IsUnionKind(kind):
- return "%s" % GetNameForKind(kind, internal=True)
- if mojom.IsArrayKind(kind):
- return ("mojo::internal::Pointer<mojo::internal::Array_Data<%s>>" %
- GetCppFieldType(kind.kind))
- if mojom.IsMapKind(kind):
- return ("mojo::internal::Pointer<mojo::internal::Map_Data<%s, %s>>" %
- (GetCppFieldType(kind.key_kind), GetCppFieldType(kind.value_kind)))
- if mojom.IsInterfaceKind(kind):
- return "mojo::internal::Interface_Data"
- if mojom.IsInterfaceRequestKind(kind):
- return "mojo::internal::Handle_Data"
- if mojom.IsAssociatedInterfaceKind(kind):
- return "mojo::internal::AssociatedInterface_Data"
- if mojom.IsAssociatedInterfaceRequestKind(kind):
- return "mojo::internal::AssociatedEndpointHandle_Data"
- if mojom.IsEnumKind(kind):
- return "int32_t"
- if mojom.IsStringKind(kind):
- return "mojo::internal::Pointer<mojo::internal::String_Data>"
- if mojom.IsAnyHandleKind(kind):
- return "mojo::internal::Handle_Data"
- return _kind_to_cpp_type[kind]
-
-def GetCppUnionFieldType(kind):
- if mojom.IsUnionKind(kind):
- return ("mojo::internal::Pointer<%s>" % GetNameForKind(kind, internal=True))
- return GetCppFieldType(kind)
-
-def GetUnionGetterReturnType(kind):
- if mojom.IsReferenceKind(kind):
- return "%s&" % GetCppWrapperType(kind)
- return GetCppWrapperType(kind)
-
-def GetUnionTraitGetterReturnType(kind):
- """Get field type used in UnionTraits template specialization.
-
- The type may be qualified as UnionTraits specializations live outside the
- namespace where e.g. structs are defined.
-
- Args:
- kind: {Kind} The type of the field.
-
- Returns:
- {str} The C++ type to use for the field.
- """
- if mojom.IsReferenceKind(kind):
- return "%s&" % GetCppWrapperType(kind, add_same_module_namespaces=True)
- return GetCppWrapperType(kind, add_same_module_namespaces=True)
-
-def GetCppDataViewType(kind, qualified=False):
- def _GetName(input_kind):
- return _NameFormatter(input_kind, None).FormatForCpp(
- add_same_module_namespaces=qualified, flatten_nested_kind=True)
-
- if mojom.IsEnumKind(kind):
- return _GetName(kind)
- if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
- return "%sDataView" % _GetName(kind)
- if mojom.IsArrayKind(kind):
- return "mojo::ArrayDataView<%s>" % GetCppDataViewType(kind.kind, qualified)
- if mojom.IsMapKind(kind):
- return ("mojo::MapDataView<%s, %s>" % (
- GetCppDataViewType(kind.key_kind, qualified),
- GetCppDataViewType(kind.value_kind, qualified)))
- if mojom.IsStringKind(kind):
- return "mojo::StringDataView"
- if mojom.IsInterfaceKind(kind):
- return "%sPtrDataView" % _GetName(kind)
- if mojom.IsInterfaceRequestKind(kind):
- return "%sRequestDataView" % _GetName(kind.kind)
- if mojom.IsAssociatedInterfaceKind(kind):
- return "%sAssociatedPtrInfoDataView" % _GetName(kind.kind)
- if mojom.IsAssociatedInterfaceRequestKind(kind):
- return "%sAssociatedRequestDataView" % _GetName(kind.kind)
- if mojom.IsGenericHandleKind(kind):
- return "mojo::ScopedHandle"
- if mojom.IsDataPipeConsumerKind(kind):
- return "mojo::ScopedDataPipeConsumerHandle"
- if mojom.IsDataPipeProducerKind(kind):
- return "mojo::ScopedDataPipeProducerHandle"
- if mojom.IsMessagePipeKind(kind):
- return "mojo::ScopedMessagePipeHandle"
- if mojom.IsSharedBufferKind(kind):
- return "mojo::ScopedSharedBufferHandle"
- return _kind_to_cpp_type[kind]
-
-def GetUnmappedTypeForSerializer(kind):
- return GetCppDataViewType(kind, qualified=True)
-
-def TranslateConstants(token, kind):
- if isinstance(token, mojom.NamedValue):
- return GetNameForKind(token, flatten_nested_kind=True)
-
- if isinstance(token, mojom.BuiltinValue):
- if token.value == "double.INFINITY":
- return "std::numeric_limits<double>::infinity()"
- if token.value == "float.INFINITY":
- return "std::numeric_limits<float>::infinity()"
- if token.value == "double.NEGATIVE_INFINITY":
- return "-std::numeric_limits<double>::infinity()"
- if token.value == "float.NEGATIVE_INFINITY":
- return "-std::numeric_limits<float>::infinity()"
- if token.value == "double.NAN":
- return "std::numeric_limits<double>::quiet_NaN()"
- if token.value == "float.NAN":
- return "std::numeric_limits<float>::quiet_NaN()"
-
- if (kind is not None and mojom.IsFloatKind(kind)):
- return token if token.isdigit() else token + "f";
-
- # Per C++11, 2.14.2, the type of an integer literal is the first of the
- # corresponding list in Table 6 in which its value can be represented. In this
- # case, the list for decimal constants with no suffix is:
- # int, long int, long long int
- # The standard considers a program ill-formed if it contains an integer
- # literal that cannot be represented by any of the allowed types.
- #
- # As it turns out, MSVC doesn't bother trying to fall back to long long int,
- # so the integral constant -2147483648 causes it grief: it decides to
- # represent 2147483648 as an unsigned integer, and then warns that the unary
- # minus operator doesn't make sense on unsigned types. Doh!
- if kind == mojom.INT32 and token == "-2147483648":
- return "(-%d - 1) /* %s */" % (
- 2**31 - 1, "Workaround for MSVC bug; see https://crbug.com/445618")
-
- return "%s%s" % (token, _kind_to_cpp_literal_suffix.get(kind, ""))
-
-def ExpressionToText(value, kind=None):
- return TranslateConstants(value, kind)
def RequiresContextForDataView(kind):
for field in kind.fields:
@@ -485,6 +160,7 @@ def RequiresContextForDataView(kind):
return True
return False
+
def ShouldInlineStruct(struct):
# TODO(darin): Base this on the size of the wrapper class.
if len(struct.fields) > 4:
@@ -494,11 +170,6 @@ def ShouldInlineStruct(struct):
return False
return True
-def ContainsMoveOnlyMembers(struct):
- for field in struct.fields:
- if IsMoveOnlyKind(field.kind):
- return True
- return False
def ShouldInlineUnion(union):
return not any(
@@ -528,134 +199,11 @@ class StructConstructor(object):
yield (field, field in self._params)
-def GetStructConstructors(struct):
- """Returns a list of constructors for a struct.
-
- Params:
- struct: {Struct} The struct to return constructors for.
-
- Returns:
- {[StructConstructor]} A list of StructConstructors that should be generated
- for |struct|.
- """
- if not mojom.IsStructKind(struct):
- raise TypeError
- # Types that are neither copyable nor movable can't be passed to a struct
- # constructor so only generate a default constructor.
- if any(IsTypemappedKind(field.kind) and _current_typemap[
- GetFullMojomNameForKind(field.kind)]["non_copyable_non_movable"]
- for field in struct.fields):
- return [StructConstructor(struct.fields, [])]
-
- param_counts = [0]
- for version in struct.versions:
- if param_counts[-1] != version.num_fields:
- param_counts.append(version.num_fields)
-
- ordinal_fields = sorted(struct.fields, key=lambda field: field.ordinal)
- return (StructConstructor(struct.fields, ordinal_fields[:param_count])
- for param_count in param_counts)
-
-
-def GetContainerValidateParamsCtorArgs(kind):
- if mojom.IsStringKind(kind):
- expected_num_elements = 0
- element_is_nullable = False
- key_validate_params = "nullptr"
- element_validate_params = "nullptr"
- enum_validate_func = "nullptr"
- elif mojom.IsMapKind(kind):
- expected_num_elements = 0
- element_is_nullable = False
- key_validate_params = GetNewContainerValidateParams(mojom.Array(
- kind=kind.key_kind))
- element_validate_params = GetNewContainerValidateParams(mojom.Array(
- kind=kind.value_kind))
- enum_validate_func = "nullptr"
- else: # mojom.IsArrayKind(kind)
- expected_num_elements = generator.ExpectedArraySize(kind) or 0
- element_is_nullable = mojom.IsNullableKind(kind.kind)
- key_validate_params = "nullptr"
- element_validate_params = GetNewContainerValidateParams(kind.kind)
- if mojom.IsEnumKind(kind.kind):
- enum_validate_func = ("%s::Validate" %
- GetQualifiedNameForKind(kind.kind, internal=True,
- flatten_nested_kind=True))
- else:
- enum_validate_func = "nullptr"
-
- if enum_validate_func == "nullptr":
- if key_validate_params == "nullptr":
- return "%d, %s, %s" % (expected_num_elements,
- "true" if element_is_nullable else "false",
- element_validate_params)
- else:
- return "%s, %s" % (key_validate_params, element_validate_params)
- else:
- return "%d, %s" % (expected_num_elements, enum_validate_func)
-
-def GetNewContainerValidateParams(kind):
- if (not mojom.IsArrayKind(kind) and not mojom.IsMapKind(kind) and
- not mojom.IsStringKind(kind)):
- return "nullptr"
-
- return "new mojo::internal::ContainerValidateParams(%s)" % (
- GetContainerValidateParamsCtorArgs(kind))
-
class Generator(generator.Generator):
+ def __init__(self, *args, **kwargs):
+ super(Generator, self).__init__(*args, **kwargs)
- cpp_filters = {
- "all_enum_values": AllEnumValues,
- "constant_value": ConstantValue,
- "contains_handles_or_interfaces": mojom.ContainsHandlesOrInterfaces,
- "contains_move_only_members": ContainsMoveOnlyMembers,
- "cpp_wrapper_param_type": GetCppWrapperParamType,
- "cpp_data_view_type": GetCppDataViewType,
- "cpp_field_type": GetCppFieldType,
- "cpp_union_field_type": GetCppUnionFieldType,
- "cpp_pod_type": GetCppPodType,
- "cpp_union_getter_return_type": GetUnionGetterReturnType,
- "cpp_union_trait_getter_return_type": GetUnionTraitGetterReturnType,
- "cpp_wrapper_type": GetCppWrapperType,
- "default_value": DefaultValue,
- "expression_to_text": ExpressionToText,
- "format_constant_declaration": FormatConstantDeclaration,
- "get_container_validate_params_ctor_args":
- GetContainerValidateParamsCtorArgs,
- "get_name_for_kind": GetNameForKind,
- "get_pad": pack.GetPad,
- "get_qualified_name_for_kind": GetQualifiedNameForKind,
- "has_callbacks": mojom.HasCallbacks,
- "has_sync_methods": mojom.HasSyncMethods,
- "requires_context_for_data_view": RequiresContextForDataView,
- "should_inline": ShouldInlineStruct,
- "should_inline_union": ShouldInlineUnion,
- "is_array_kind": mojom.IsArrayKind,
- "is_enum_kind": mojom.IsEnumKind,
- "is_integral_kind": mojom.IsIntegralKind,
- "is_native_only_kind": IsNativeOnlyKind,
- "is_any_handle_kind": mojom.IsAnyHandleKind,
- "is_any_interface_kind": mojom.IsAnyInterfaceKind,
- "is_any_handle_or_interface_kind": mojom.IsAnyHandleOrInterfaceKind,
- "is_associated_kind": mojom.IsAssociatedKind,
- "is_hashable": IsHashableKind,
- "is_map_kind": mojom.IsMapKind,
- "is_nullable_kind": mojom.IsNullableKind,
- "is_object_kind": mojom.IsObjectKind,
- "is_reference_kind": mojom.IsReferenceKind,
- "is_string_kind": mojom.IsStringKind,
- "is_struct_kind": mojom.IsStructKind,
- "is_typemapped_kind": IsTypemappedKind,
- "is_union_kind": mojom.IsUnionKind,
- "passes_associated_kinds": mojom.PassesAssociatedKinds,
- "struct_constructors": GetStructConstructors,
- "stylize_method": generator.StudlyCapsToCamel,
- "under_to_camel": generator.UnderToCamel,
- "unmapped_type_for_serializer": GetUnmappedTypeForSerializer,
- "wtf_hash_fn_name_for_enum": GetWtfHashFnNameForEnum,
- }
-
- def GetExtraTraitsHeaders(self):
+ def _GetExtraTraitsHeaders(self):
extra_headers = set()
for typemap in self._GetAllUsedTypemaps():
extra_headers.update(typemap.get("traits_headers", []))
@@ -684,12 +232,12 @@ class Generator(generator.Generator):
AddKind(kind.key_kind)
AddKind(kind.value_kind)
else:
- name = GetFullMojomNameForKind(kind)
+ name = self._GetFullMojomNameForKind(kind)
if name in seen_types:
return
seen_types.add(name)
- typemap = _current_typemap.get(name, None)
+ typemap = self.typemap.get(name, None)
if typemap:
used_typemaps.append(typemap)
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
@@ -707,14 +255,14 @@ class Generator(generator.Generator):
return used_typemaps
- def GetExtraPublicHeaders(self):
+ def _GetExtraPublicHeaders(self):
all_enums = list(self.module.enums)
for struct in self.module.structs:
all_enums.extend(struct.enums)
for interface in self.module.interfaces:
all_enums.extend(interface.enums)
- types = set(GetFullMojomNameForKind(typename)
+ types = set(self._GetFullMojomNameForKind(typename)
for typename in
self.module.structs + all_enums + self.module.unions)
headers = set()
@@ -733,86 +281,600 @@ class Generator(generator.Generator):
for param in method.parameters + (method.response_parameters or []):
yield param.kind
- def GetJinjaExports(self):
- structs = self.GetStructs()
- interfaces = self.GetInterfaces()
+ def _GetJinjaExports(self):
all_enums = list(self.module.enums)
- for struct in structs:
+ for struct in self.module.structs:
all_enums.extend(struct.enums)
- for interface in interfaces:
+ for interface in self.module.interfaces:
all_enums.extend(interface.enums)
return {
+ "all_enums": all_enums,
+ "disallow_interfaces": self.disallow_interfaces,
+ "disallow_native_types": self.disallow_native_types,
+ "enums": self.module.enums,
+ "export_attribute": self.export_attribute,
+ "export_header": self.export_header,
+ "extra_public_headers": self._GetExtraPublicHeaders(),
+ "extra_traits_headers": self._GetExtraTraitsHeaders(),
+ "for_blink": self.for_blink,
+ "imports": self.module.imports,
+ "interfaces": self.module.interfaces,
+ "kinds": self.module.kinds,
"module": self.module,
"namespace": self.module.namespace,
"namespaces_as_array": NamespaceToArray(self.module.namespace),
- "imports": self.module.imports,
- "kinds": self.module.kinds,
- "enums": self.module.enums,
- "all_enums": all_enums,
- "structs": structs,
- "unions": self.GetUnions(),
- "interfaces": interfaces,
- "variant": self.variant,
- "extra_traits_headers": self.GetExtraTraitsHeaders(),
- "extra_public_headers": self.GetExtraPublicHeaders(),
- "for_blink": self.for_blink,
+ "structs": self.module.structs,
+ "support_lazy_serialization": self.support_lazy_serialization,
+ "unions": self.module.unions,
"use_once_callback": self.use_once_callback,
- "export_attribute": self.export_attribute,
- "export_header": self.export_header,
+ "variant": self.variant,
}
@staticmethod
def GetTemplatePrefix():
return "cpp_templates"
- @classmethod
- def GetFilters(cls):
- return cls.cpp_filters
+ def GetFilters(self):
+ cpp_filters = {
+ "all_enum_values": AllEnumValues,
+ "constant_value": self._ConstantValue,
+ "contains_handles_or_interfaces": mojom.ContainsHandlesOrInterfaces,
+ "contains_move_only_members": self._ContainsMoveOnlyMembers,
+ "cpp_data_view_type": self._GetCppDataViewType,
+ "cpp_field_type": self._GetCppFieldType,
+ "cpp_union_field_type": self._GetCppUnionFieldType,
+ "cpp_pod_type": GetCppPodType,
+ "cpp_union_getter_return_type": self._GetUnionGetterReturnType,
+ "cpp_union_trait_getter_return_type": self._GetUnionTraitGetterReturnType,
+ "cpp_wrapper_call_type": self._GetCppWrapperCallType,
+ "cpp_wrapper_param_type": self._GetCppWrapperParamType,
+ "cpp_wrapper_param_type_new": self._GetCppWrapperParamTypeNew,
+ "cpp_wrapper_type": self._GetCppWrapperType,
+ "default_value": self._DefaultValue,
+ "expression_to_text": self._ExpressionToText,
+ "format_constant_declaration": self._FormatConstantDeclaration,
+ "get_container_validate_params_ctor_args":
+ self._GetContainerValidateParamsCtorArgs,
+ "get_name_for_kind": self._GetNameForKind,
+ "get_pad": pack.GetPad,
+ "get_qualified_name_for_kind": self._GetQualifiedNameForKind,
+ "has_callbacks": mojom.HasCallbacks,
+ "has_sync_methods": mojom.HasSyncMethods,
+ "method_supports_lazy_serialization":
+ self._MethodSupportsLazySerialization,
+ "requires_context_for_data_view": RequiresContextForDataView,
+ "should_inline": ShouldInlineStruct,
+ "should_inline_union": ShouldInlineUnion,
+ "is_array_kind": mojom.IsArrayKind,
+ "is_enum_kind": mojom.IsEnumKind,
+ "is_integral_kind": mojom.IsIntegralKind,
+ "is_interface_kind": mojom.IsInterfaceKind,
+ "is_native_only_kind": IsNativeOnlyKind,
+ "is_any_handle_kind": mojom.IsAnyHandleKind,
+ "is_any_interface_kind": mojom.IsAnyInterfaceKind,
+ "is_any_handle_or_interface_kind": mojom.IsAnyHandleOrInterfaceKind,
+ "is_associated_kind": mojom.IsAssociatedKind,
+ "is_hashable": self._IsHashableKind,
+ "is_map_kind": mojom.IsMapKind,
+ "is_nullable_kind": mojom.IsNullableKind,
+ "is_object_kind": mojom.IsObjectKind,
+ "is_reference_kind": mojom.IsReferenceKind,
+ "is_string_kind": mojom.IsStringKind,
+ "is_struct_kind": mojom.IsStructKind,
+ "is_typemapped_kind": self._IsTypemappedKind,
+ "is_union_kind": mojom.IsUnionKind,
+ "passes_associated_kinds": mojom.PassesAssociatedKinds,
+ "struct_constructors": self._GetStructConstructors,
+ "under_to_camel": generator.ToCamel,
+ "unmapped_type_for_serializer": self._GetUnmappedTypeForSerializer,
+ "use_custom_serializer": UseCustomSerializer,
+ "wtf_hash_fn_name_for_enum": GetWtfHashFnNameForEnum,
+ }
+ return cpp_filters
@UseJinja("module.h.tmpl")
- def GenerateModuleHeader(self):
- return self.GetJinjaExports()
+ def _GenerateModuleHeader(self):
+ return self._GetJinjaExports()
@UseJinja("module.cc.tmpl")
- def GenerateModuleSource(self):
- return self.GetJinjaExports()
+ def _GenerateModuleSource(self):
+ return self._GetJinjaExports()
@UseJinja("module-shared.h.tmpl")
- def GenerateModuleSharedHeader(self):
- return self.GetJinjaExports()
+ def _GenerateModuleSharedHeader(self):
+ return self._GetJinjaExports()
@UseJinja("module-shared-internal.h.tmpl")
- def GenerateModuleSharedInternalHeader(self):
- return self.GetJinjaExports()
+ def _GenerateModuleSharedInternalHeader(self):
+ return self._GetJinjaExports()
+
+ @UseJinja("module-shared-message-ids.h.tmpl")
+ def _GenerateModuleSharedMessageIdsHeader(self):
+ return self._GetJinjaExports()
@UseJinja("module-shared.cc.tmpl")
- def GenerateModuleSharedSource(self):
- return self.GetJinjaExports()
+ def _GenerateModuleSharedSource(self):
+ return self._GetJinjaExports()
def GenerateFiles(self, args):
+ self.module.Stylize(generator.Stylizer())
+
if self.generate_non_variant_code:
- self.Write(self.GenerateModuleSharedHeader(),
- self.MatchMojomFilePath("%s-shared.h" % self.module.name))
- self.Write(
- self.GenerateModuleSharedInternalHeader(),
- self.MatchMojomFilePath("%s-shared-internal.h" % self.module.name))
- self.Write(self.GenerateModuleSharedSource(),
- self.MatchMojomFilePath("%s-shared.cc" % self.module.name))
+ if self.generate_message_ids:
+ self.Write(self._GenerateModuleSharedMessageIdsHeader(),
+ "%s-shared-message-ids.h" % self.module.path)
+ else:
+ self.Write(self._GenerateModuleSharedHeader(),
+ "%s-shared.h" % self.module.path)
+ self.Write(self._GenerateModuleSharedInternalHeader(),
+ "%s-shared-internal.h" % self.module.path)
+ self.Write(self._GenerateModuleSharedSource(),
+ "%s-shared.cc" % self.module.path)
else:
- global _current_typemap
- _current_typemap = self.typemap
- global _for_blink
- _for_blink = self.for_blink
- global _use_once_callback
- _use_once_callback = self.use_once_callback
- global _variant
- _variant = self.variant
- global _export_attribute
- _export_attribute = self.export_attribute
suffix = "-%s" % self.variant if self.variant else ""
- self.Write(self.GenerateModuleHeader(),
- self.MatchMojomFilePath("%s%s.h" % (self.module.name, suffix)))
- self.Write(
- self.GenerateModuleSource(),
- self.MatchMojomFilePath("%s%s.cc" % (self.module.name, suffix)))
+ self.Write(self._GenerateModuleHeader(),
+ "%s%s.h" % (self.module.path, suffix))
+ self.Write(self._GenerateModuleSource(),
+ "%s%s.cc" % (self.module.path, suffix))
+
+ def _ConstantValue(self, constant):
+ return self._ExpressionToText(constant.value, kind=constant.kind)
+
+ def _DefaultValue(self, field):
+ if not field.default:
+ return ""
+
+ if mojom.IsStructKind(field.kind):
+ assert field.default == "default"
+ if self._IsTypemappedKind(field.kind):
+ return ""
+ return "%s::New()" % self._GetNameForKind(field.kind)
+
+ expression = self._ExpressionToText(field.default, kind=field.kind)
+ if mojom.IsEnumKind(field.kind) and self._IsTypemappedKind(field.kind):
+ expression = "mojo::internal::ConvertEnumValue<%s, %s>(%s)" % (
+ self._GetNameForKind(field.kind), self._GetCppWrapperType(field.kind),
+ expression)
+ return expression
+
+ def _GetNameForKind(self, kind, internal=False, flatten_nested_kind=False,
+ add_same_module_namespaces=False):
+ return _NameFormatter(kind, self.variant).FormatForCpp(
+ internal=internal, flatten_nested_kind=flatten_nested_kind,
+ omit_namespace_for_module = (None if add_same_module_namespaces
+ else self.module))
+
+ def _GetQualifiedNameForKind(self, kind, internal=False,
+ flatten_nested_kind=False, include_variant=True):
+ return _NameFormatter(
+ kind, self.variant if include_variant else None).FormatForCpp(
+ internal=internal, flatten_nested_kind=flatten_nested_kind)
+
+ def _GetFullMojomNameForKind(self, kind):
+ return _NameFormatter(kind, self.variant).FormatForMojom()
+
+ def _IsTypemappedKind(self, kind):
+ return hasattr(kind, "name") and \
+ self._GetFullMojomNameForKind(kind) in self.typemap
+
+ def _IsHashableKind(self, kind):
+ """Check if the kind can be hashed.
+
+ Args:
+ kind: {Kind} The kind to check.
+
+ Returns:
+ {bool} True if a value of this kind can be hashed.
+ """
+ checked = set()
+ def Check(kind):
+ if kind.spec in checked:
+ return True
+ checked.add(kind.spec)
+ if mojom.IsNullableKind(kind):
+ return False
+ elif mojom.IsStructKind(kind):
+ if kind.native_only:
+ return False
+ if (self._IsTypemappedKind(kind) and
+ not self.typemap[self._GetFullMojomNameForKind(kind)]["hashable"]):
+ return False
+ return all(Check(field.kind) for field in kind.fields)
+ elif mojom.IsEnumKind(kind):
+ return not self._IsTypemappedKind(kind) or self.typemap[
+ self._GetFullMojomNameForKind(kind)]["hashable"]
+ elif mojom.IsUnionKind(kind):
+ return all(Check(field.kind) for field in kind.fields)
+ elif mojom.IsAnyHandleKind(kind):
+ return False
+ elif mojom.IsAnyInterfaceKind(kind):
+ return False
+ # TODO(crbug.com/735301): Arrays and maps could be made hashable. We just
+ # don't have a use case yet.
+ elif mojom.IsArrayKind(kind):
+ return False
+ elif mojom.IsMapKind(kind):
+ return False
+ else:
+ return True
+ return Check(kind)
+
+ def _GetNativeTypeName(self, typemapped_kind):
+ return self.typemap[self._GetFullMojomNameForKind(typemapped_kind)][
+ "typename"]
+
+ def _FormatConstantDeclaration(self, constant, nested=False):
+ if mojom.IsStringKind(constant.kind):
+ if nested:
+ return "const char %s[]" % constant.name
+ return "%sextern const char %s[]" % \
+ ((self.export_attribute + " ") if self.export_attribute else "",
+ constant.name)
+ return "constexpr %s %s = %s" % (
+ GetCppPodType(constant.kind), constant.name,
+ self._ConstantValue(constant))
+
+ def _GetCppWrapperType(self, kind, add_same_module_namespaces=False):
+ def _AddOptional(type_name):
+ return "base::Optional<%s>" % type_name
+
+ if self._IsTypemappedKind(kind):
+ type_name = self._GetNativeTypeName(kind)
+ if (mojom.IsNullableKind(kind) and
+ not self.typemap[self._GetFullMojomNameForKind(kind)][
+ "nullable_is_same_type"]):
+ type_name = _AddOptional(type_name)
+ return type_name
+ if mojom.IsEnumKind(kind):
+ return self._GetNameForKind(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
+ if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
+ return "%sPtr" % self._GetNameForKind(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
+ if mojom.IsArrayKind(kind):
+ pattern = "WTF::Vector<%s>" if self.for_blink else "std::vector<%s>"
+ if mojom.IsNullableKind(kind):
+ pattern = _AddOptional(pattern)
+ return pattern % self._GetCppWrapperType(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ if mojom.IsMapKind(kind):
+ pattern = ("WTF::HashMap<%s, %s>" if self.for_blink else
+ "base::flat_map<%s, %s>")
+ if mojom.IsNullableKind(kind):
+ pattern = _AddOptional(pattern)
+ return pattern % (
+ self._GetCppWrapperType(
+ kind.key_kind,
+ add_same_module_namespaces=add_same_module_namespaces),
+ self._GetCppWrapperType(
+ kind.value_kind,
+ add_same_module_namespaces=add_same_module_namespaces))
+ if mojom.IsInterfaceKind(kind):
+ return "%sPtrInfo" % self._GetNameForKind(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
+ if mojom.IsInterfaceRequestKind(kind):
+ return "%sRequest" % self._GetNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ if mojom.IsAssociatedInterfaceKind(kind):
+ return "%sAssociatedPtrInfo" % self._GetNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ if mojom.IsAssociatedInterfaceRequestKind(kind):
+ return "%sAssociatedRequest" % self._GetNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ if mojom.IsStringKind(kind):
+ if self.for_blink:
+ return "WTF::String"
+ type_name = "std::string"
+ return (_AddOptional(type_name) if mojom.IsNullableKind(kind)
+ else type_name)
+ if mojom.IsGenericHandleKind(kind):
+ return "mojo::ScopedHandle"
+ if mojom.IsDataPipeConsumerKind(kind):
+ return "mojo::ScopedDataPipeConsumerHandle"
+ if mojom.IsDataPipeProducerKind(kind):
+ return "mojo::ScopedDataPipeProducerHandle"
+ if mojom.IsMessagePipeKind(kind):
+ return "mojo::ScopedMessagePipeHandle"
+ if mojom.IsSharedBufferKind(kind):
+ return "mojo::ScopedSharedBufferHandle"
+ if not kind in _kind_to_cpp_type:
+ raise Exception("Unrecognized kind %s" % kind.spec)
+ return _kind_to_cpp_type[kind]
+
+ def _IsMoveOnlyKind(self, kind):
+ if self._IsTypemappedKind(kind):
+ if mojom.IsEnumKind(kind):
+ return False
+ return self.typemap[self._GetFullMojomNameForKind(kind)]["move_only"]
+ if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
+ return True
+ if mojom.IsArrayKind(kind):
+ return self._IsMoveOnlyKind(kind.kind)
+ if mojom.IsMapKind(kind):
+ return (self._IsMoveOnlyKind(kind.value_kind) or
+ self._IsMoveOnlyKind(kind.key_kind))
+ if mojom.IsAnyHandleOrInterfaceKind(kind):
+ return True
+ return False
+
+ def _IsCopyablePassByValue(self, kind):
+ if not self._IsTypemappedKind(kind):
+ return False
+ return self.typemap[self._GetFullMojomNameForKind(kind)][
+ "copyable_pass_by_value"]
+
+ def _ShouldPassParamByValue(self, kind):
+ return ((not mojom.IsReferenceKind(kind)) or self._IsMoveOnlyKind(kind) or
+ self._IsCopyablePassByValue(kind))
+
+ def _GetCppWrapperCallType(self, kind):
+ # TODO: Remove this once interfaces are always passed as PtrInfo.
+ if mojom.IsInterfaceKind(kind):
+ return "%sPtr" % self._GetNameForKind(kind)
+ return self._GetCppWrapperType(kind)
+
+ def _GetCppWrapperParamType(self, kind):
+ # TODO: Remove all usage of this method in favor of
+ # _GetCppWrapperParamTypeNew. This requires all generated code which passes
+ # interface handles to use PtrInfo instead of Ptr.
+ if mojom.IsInterfaceKind(kind):
+ return "%sPtr" % self._GetNameForKind(kind)
+ cpp_wrapper_type = self._GetCppWrapperType(kind)
+ return (cpp_wrapper_type if self._ShouldPassParamByValue(kind)
+ else "const %s&" % cpp_wrapper_type)
+
+ def _GetCppWrapperParamTypeNew(self, kind):
+ cpp_wrapper_type = self._GetCppWrapperType(kind)
+ return (cpp_wrapper_type if self._ShouldPassParamByValue(kind)
+ else "const %s&" % cpp_wrapper_type)
+
+ def _GetCppFieldType(self, kind):
+ if mojom.IsStructKind(kind):
+ return ("mojo::internal::Pointer<%s>" %
+ self._GetNameForKind(kind, internal=True))
+ if mojom.IsUnionKind(kind):
+ return "%s" % self._GetNameForKind(kind, internal=True)
+ if mojom.IsArrayKind(kind):
+ return ("mojo::internal::Pointer<mojo::internal::Array_Data<%s>>" %
+ self._GetCppFieldType(kind.kind))
+ if mojom.IsMapKind(kind):
+ return ("mojo::internal::Pointer<mojo::internal::Map_Data<%s, %s>>" %
+ (self._GetCppFieldType(kind.key_kind),
+ self._GetCppFieldType(kind.value_kind)))
+ if mojom.IsInterfaceKind(kind):
+ return "mojo::internal::Interface_Data"
+ if mojom.IsInterfaceRequestKind(kind):
+ return "mojo::internal::Handle_Data"
+ if mojom.IsAssociatedInterfaceKind(kind):
+ return "mojo::internal::AssociatedInterface_Data"
+ if mojom.IsAssociatedInterfaceRequestKind(kind):
+ return "mojo::internal::AssociatedEndpointHandle_Data"
+ if mojom.IsEnumKind(kind):
+ return "int32_t"
+ if mojom.IsStringKind(kind):
+ return "mojo::internal::Pointer<mojo::internal::String_Data>"
+ if mojom.IsAnyHandleKind(kind):
+ return "mojo::internal::Handle_Data"
+ return _kind_to_cpp_type[kind]
+
+ def _GetCppUnionFieldType(self, kind):
+ if mojom.IsUnionKind(kind):
+ return ("mojo::internal::Pointer<%s>" %
+ self._GetNameForKind(kind, internal=True))
+ return self._GetCppFieldType(kind)
+
+ def _GetUnionGetterReturnType(self, kind):
+ if mojom.IsReferenceKind(kind):
+ return "%s&" % self._GetCppWrapperType(kind)
+ return self._GetCppWrapperType(kind)
+
+ def _GetUnionTraitGetterReturnType(self, kind):
+ """Get field type used in UnionTraits template specialization.
+
+ The type may be qualified as UnionTraits specializations live outside the
+ namespace where e.g. structs are defined.
+
+ Args:
+ kind: {Kind} The type of the field.
+
+ Returns:
+ {str} The C++ type to use for the field.
+ """
+ if mojom.IsReferenceKind(kind):
+ return "%s&" % self._GetCppWrapperType(kind,
+ add_same_module_namespaces=True)
+ return self._GetCppWrapperType(kind, add_same_module_namespaces=True)
+
+ def _KindMustBeSerialized(self, kind, processed_kinds=None):
+ if not processed_kinds:
+ processed_kinds = set()
+ if kind in processed_kinds:
+ return False
+
+ if (self._IsTypemappedKind(kind) and
+ self.typemap[self._GetFullMojomNameForKind(kind)]["force_serialize"]):
+ return True
+
+ processed_kinds.add(kind)
+
+ if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
+ return any(self._KindMustBeSerialized(field.kind,
+ processed_kinds=processed_kinds)
+ for field in kind.fields)
+
+ return False
+
+ def _MethodSupportsLazySerialization(self, method):
+ if not self.support_lazy_serialization:
+ return False
+
+ # TODO(crbug.com/753433): Support lazy serialization for methods which pass
+ # associated handles.
+ if mojom.MethodPassesAssociatedKinds(method):
+ return False
+
+ return not any(self._KindMustBeSerialized(param.kind) for param in
+ method.parameters + (method.response_parameters or []))
+
+ def _TranslateConstants(self, token, kind):
+ if isinstance(token, mojom.NamedValue):
+ return self._GetNameForKind(token, flatten_nested_kind=True)
+
+ if isinstance(token, mojom.BuiltinValue):
+ if token.value == "double.INFINITY":
+ return "std::numeric_limits<double>::infinity()"
+ if token.value == "float.INFINITY":
+ return "std::numeric_limits<float>::infinity()"
+ if token.value == "double.NEGATIVE_INFINITY":
+ return "-std::numeric_limits<double>::infinity()"
+ if token.value == "float.NEGATIVE_INFINITY":
+ return "-std::numeric_limits<float>::infinity()"
+ if token.value == "double.NAN":
+ return "std::numeric_limits<double>::quiet_NaN()"
+ if token.value == "float.NAN":
+ return "std::numeric_limits<float>::quiet_NaN()"
+
+ if (kind is not None and mojom.IsFloatKind(kind)):
+ return token if token.isdigit() else token + "f";
+
+ # Per C++11, 2.14.2, the type of an integer literal is the first of the
+ # corresponding list in Table 6 in which its value can be represented. In
+ # this case, the list for decimal constants with no suffix is:
+ # int, long int, long long int
+ # The standard considers a program ill-formed if it contains an integer
+ # literal that cannot be represented by any of the allowed types.
+ #
+ # As it turns out, MSVC doesn't bother trying to fall back to long long int,
+ # so the integral constant -2147483648 causes it grief: it decides to
+ # represent 2147483648 as an unsigned integer, and then warns that the unary
+ # minus operator doesn't make sense on unsigned types. Doh!
+ if kind == mojom.INT32 and token == "-2147483648":
+ return "(-%d - 1) /* %s */" % (
+ 2**31 - 1, "Workaround for MSVC bug; see https://crbug.com/445618")
+
+ return "%s%s" % (token, _kind_to_cpp_literal_suffix.get(kind, ""))
+
+ def _ExpressionToText(self, value, kind=None):
+ return self._TranslateConstants(value, kind)
+
+ def _ContainsMoveOnlyMembers(self, struct):
+ for field in struct.fields:
+ if self._IsMoveOnlyKind(field.kind):
+ return True
+ return False
+
+ def _GetStructConstructors(self, struct):
+ """Returns a list of constructors for a struct.
+
+ Params:
+ struct: {Struct} The struct to return constructors for.
+
+ Returns:
+ {[StructConstructor]} A list of StructConstructors that should be
+ generated for |struct|.
+ """
+ if not mojom.IsStructKind(struct):
+ raise TypeError
+ # Types that are neither copyable nor movable can't be passed to a struct
+ # constructor so only generate a default constructor.
+ if any(self._IsTypemappedKind(field.kind) and self.typemap[
+ self._GetFullMojomNameForKind(field.kind)]["non_copyable_non_movable"]
+ for field in struct.fields):
+ return [StructConstructor(struct.fields, [])]
+
+ param_counts = [0]
+ for version in struct.versions:
+ if param_counts[-1] != version.num_fields:
+ param_counts.append(version.num_fields)
+
+ ordinal_fields = sorted(struct.fields, key=lambda field: field.ordinal)
+ return (StructConstructor(struct.fields, ordinal_fields[:param_count])
+ for param_count in param_counts)
+
+ def _GetContainerValidateParamsCtorArgs(self, kind):
+ if mojom.IsStringKind(kind):
+ expected_num_elements = 0
+ element_is_nullable = False
+ key_validate_params = "nullptr"
+ element_validate_params = "nullptr"
+ enum_validate_func = "nullptr"
+ elif mojom.IsMapKind(kind):
+ expected_num_elements = 0
+ element_is_nullable = False
+ key_validate_params = self._GetNewContainerValidateParams(mojom.Array(
+ kind=kind.key_kind))
+ element_validate_params = self._GetNewContainerValidateParams(mojom.Array(
+ kind=kind.value_kind))
+ enum_validate_func = "nullptr"
+ else: # mojom.IsArrayKind(kind)
+ expected_num_elements = generator.ExpectedArraySize(kind) or 0
+ element_is_nullable = mojom.IsNullableKind(kind.kind)
+ key_validate_params = "nullptr"
+ element_validate_params = self._GetNewContainerValidateParams(kind.kind)
+ if mojom.IsEnumKind(kind.kind):
+ enum_validate_func = ("%s::Validate" %
+ self._GetQualifiedNameForKind(kind.kind, internal=True,
+ flatten_nested_kind=True))
+ else:
+ enum_validate_func = "nullptr"
+
+ if enum_validate_func == "nullptr":
+ if key_validate_params == "nullptr":
+ return "%d, %s, %s" % (expected_num_elements,
+ "true" if element_is_nullable else "false",
+ element_validate_params)
+ else:
+ return "%s, %s" % (key_validate_params, element_validate_params)
+ else:
+ return "%d, %s" % (expected_num_elements, enum_validate_func)
+
+ def _GetNewContainerValidateParams(self, kind):
+ if (not mojom.IsArrayKind(kind) and not mojom.IsMapKind(kind) and
+ not mojom.IsStringKind(kind)):
+ return "nullptr"
+
+ return "new mojo::internal::ContainerValidateParams(%s)" % (
+ self._GetContainerValidateParamsCtorArgs(kind))
+
+ def _GetCppDataViewType(self, kind, qualified=False):
+ def _GetName(input_kind):
+ return _NameFormatter(input_kind, None).FormatForCpp(
+ omit_namespace_for_module=(None if qualified else self.module),
+ flatten_nested_kind=True)
+
+ if mojom.IsEnumKind(kind):
+ return _GetName(kind)
+ if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
+ return "%sDataView" % _GetName(kind)
+ if mojom.IsArrayKind(kind):
+ return "mojo::ArrayDataView<%s>" % (
+ self._GetCppDataViewType(kind.kind, qualified))
+ if mojom.IsMapKind(kind):
+ return ("mojo::MapDataView<%s, %s>" % (
+ self._GetCppDataViewType(kind.key_kind, qualified),
+ self._GetCppDataViewType(kind.value_kind, qualified)))
+ if mojom.IsStringKind(kind):
+ return "mojo::StringDataView"
+ if mojom.IsInterfaceKind(kind):
+ return "%sPtrDataView" % _GetName(kind)
+ if mojom.IsInterfaceRequestKind(kind):
+ return "%sRequestDataView" % _GetName(kind.kind)
+ if mojom.IsAssociatedInterfaceKind(kind):
+ return "%sAssociatedPtrInfoDataView" % _GetName(kind.kind)
+ if mojom.IsAssociatedInterfaceRequestKind(kind):
+ return "%sAssociatedRequestDataView" % _GetName(kind.kind)
+ if mojom.IsGenericHandleKind(kind):
+ return "mojo::ScopedHandle"
+ if mojom.IsDataPipeConsumerKind(kind):
+ return "mojo::ScopedDataPipeConsumerHandle"
+ if mojom.IsDataPipeProducerKind(kind):
+ return "mojo::ScopedDataPipeProducerHandle"
+ if mojom.IsMessagePipeKind(kind):
+ return "mojo::ScopedMessagePipeHandle"
+ if mojom.IsSharedBufferKind(kind):
+ return "mojo::ScopedSharedBufferHandle"
+ return _kind_to_cpp_type[kind]
+
+ def _GetUnmappedTypeForSerializer(self, kind):
+ return self._GetCppDataViewType(kind, qualified=True)
diff --git a/mojo/public/tools/bindings/generators/mojom_java_generator.py b/mojo/public/tools/bindings/generators/mojom_java_generator.py
index c7657ff99a..0f2b618182 100644
--- a/mojo/public/tools/bindings/generators/mojom_java_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_java_generator.py
@@ -93,14 +93,22 @@ _java_primitive_to_boxed_type = {
'short': 'Short',
}
+_java_reserved_types = [
+ # These two may clash with commonly used classes on Android.
+ 'Manifest',
+ 'R'
+]
def NameToComponent(name):
- # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar ->
- # HTTP_Entry2_FooBar)
- name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name)
- # insert '_' between non upper and start of upper blocks (e.g.,
- # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar)
- name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name)
+ """ Returns a list of lowercase words corresponding to a given name. """
+ # Add underscores after uppercase letters when appropriate. An uppercase
+ # letter is considered the end of a word if it is followed by an upper and a
+ # lower. E.g. URLLoaderFactory -> URL_LoaderFactory
+ name = re.sub('([A-Z][0-9]*)(?=[A-Z][0-9]*[a-z])', r'\1_', name)
+ # Add underscores after lowercase letters when appropriate. A lowercase letter
+ # is considered the end of a word if it is followed by an upper.
+ # E.g. URLLoaderFactory -> URLLoader_Factory
+ name = re.sub('([a-z][0-9]*)(?=[A-Z])', r'\1_', name)
return [x.lower() for x in name.split('_')]
def UpperCamelCase(name):
@@ -122,7 +130,10 @@ def ConstantStyle(name):
def GetNameForElement(element):
if (mojom.IsEnumKind(element) or mojom.IsInterfaceKind(element) or
mojom.IsStructKind(element) or mojom.IsUnionKind(element)):
- return UpperCamelCase(element.name)
+ name = UpperCamelCase(element.name)
+ if name in _java_reserved_types:
+ return name + '_'
+ return name
if mojom.IsInterfaceRequestKind(element) or mojom.IsAssociatedKind(element):
return GetNameForElement(element.kind)
if isinstance(element, (mojom.Method,
@@ -403,39 +414,7 @@ def TempDir():
shutil.rmtree(dirname)
class Generator(generator.Generator):
-
- java_filters = {
- 'array_expected_length': GetArrayExpectedLength,
- 'array': GetArrayKind,
- 'constant_value': ConstantValue,
- 'decode_method': DecodeMethod,
- 'default_value': DefaultValue,
- 'encode_method': EncodeMethod,
- 'expression_to_text': ExpressionToText,
- 'has_method_without_response': HasMethodWithoutResponse,
- 'has_method_with_response': HasMethodWithResponse,
- 'interface_response_name': GetInterfaceResponseName,
- 'is_array_kind': mojom.IsArrayKind,
- 'is_any_handle_kind': mojom.IsAnyHandleKind,
- "is_enum_kind": mojom.IsEnumKind,
- 'is_interface_request_kind': mojom.IsInterfaceRequestKind,
- 'is_map_kind': mojom.IsMapKind,
- 'is_nullable_kind': mojom.IsNullableKind,
- 'is_pointer_array_kind': IsPointerArrayKind,
- 'is_reference_kind': mojom.IsReferenceKind,
- 'is_struct_kind': mojom.IsStructKind,
- 'is_union_array_kind': IsUnionArrayKind,
- 'is_union_kind': mojom.IsUnionKind,
- 'java_class_for_enum': GetJavaClassForEnum,
- 'java_true_false': GetJavaTrueFalse,
- 'java_type': GetJavaType,
- 'method_ordinal_name': GetMethodOrdinalName,
- 'name': GetNameForElement,
- 'new_array': NewArray,
- 'ucc': lambda x: UpperCamelCase(x.name),
- }
-
- def GetJinjaExports(self):
+ def _GetJinjaExports(self):
return {
'package': GetPackage(self.module),
}
@@ -444,73 +423,100 @@ class Generator(generator.Generator):
def GetTemplatePrefix():
return "java_templates"
- @classmethod
- def GetFilters(cls):
- return cls.java_filters
+ def GetFilters(self):
+ java_filters = {
+ 'array_expected_length': GetArrayExpectedLength,
+ 'array': GetArrayKind,
+ 'constant_value': ConstantValue,
+ 'decode_method': DecodeMethod,
+ 'default_value': DefaultValue,
+ 'encode_method': EncodeMethod,
+ 'expression_to_text': ExpressionToText,
+ 'has_method_without_response': HasMethodWithoutResponse,
+ 'has_method_with_response': HasMethodWithResponse,
+ 'interface_response_name': GetInterfaceResponseName,
+ 'is_array_kind': mojom.IsArrayKind,
+ 'is_any_handle_kind': mojom.IsAnyHandleKind,
+ "is_enum_kind": mojom.IsEnumKind,
+ 'is_interface_request_kind': mojom.IsInterfaceRequestKind,
+ 'is_map_kind': mojom.IsMapKind,
+ 'is_nullable_kind': mojom.IsNullableKind,
+ 'is_pointer_array_kind': IsPointerArrayKind,
+ 'is_reference_kind': mojom.IsReferenceKind,
+ 'is_struct_kind': mojom.IsStructKind,
+ 'is_union_array_kind': IsUnionArrayKind,
+ 'is_union_kind': mojom.IsUnionKind,
+ 'java_class_for_enum': GetJavaClassForEnum,
+ 'java_true_false': GetJavaTrueFalse,
+ 'java_type': GetJavaType,
+ 'method_ordinal_name': GetMethodOrdinalName,
+ 'name': GetNameForElement,
+ 'new_array': NewArray,
+ 'ucc': lambda x: UpperCamelCase(x.name),
+ }
+ return java_filters
- def GetJinjaExportsForInterface(self, interface):
- exports = self.GetJinjaExports()
+ def _GetJinjaExportsForInterface(self, interface):
+ exports = self._GetJinjaExports()
exports.update({'interface': interface})
return exports
@UseJinja('enum.java.tmpl')
- def GenerateEnumSource(self, enum):
- exports = self.GetJinjaExports()
+ def _GenerateEnumSource(self, enum):
+ exports = self._GetJinjaExports()
exports.update({'enum': enum})
return exports
@UseJinja('struct.java.tmpl')
- def GenerateStructSource(self, struct):
- exports = self.GetJinjaExports()
+ def _GenerateStructSource(self, struct):
+ exports = self._GetJinjaExports()
exports.update({'struct': struct})
return exports
@UseJinja('union.java.tmpl')
- def GenerateUnionSource(self, union):
- exports = self.GetJinjaExports()
+ def _GenerateUnionSource(self, union):
+ exports = self._GetJinjaExports()
exports.update({'union': union})
return exports
@UseJinja('interface.java.tmpl')
- def GenerateInterfaceSource(self, interface):
- return self.GetJinjaExportsForInterface(interface)
+ def _GenerateInterfaceSource(self, interface):
+ return self._GetJinjaExportsForInterface(interface)
@UseJinja('interface_internal.java.tmpl')
- def GenerateInterfaceInternalSource(self, interface):
- return self.GetJinjaExportsForInterface(interface)
+ def _GenerateInterfaceInternalSource(self, interface):
+ return self._GetJinjaExportsForInterface(interface)
@UseJinja('constants.java.tmpl')
- def GenerateConstantsSource(self, module):
- exports = self.GetJinjaExports()
+ def _GenerateConstantsSource(self, module):
+ exports = self._GetJinjaExports()
exports.update({'main_entity': GetConstantsMainEntityName(module),
'constants': module.constants})
return exports
- def DoGenerateFiles(self):
+ def _DoGenerateFiles(self):
fileutil.EnsureDirectoryExists(self.output_dir)
- # Keep this above the others as .GetStructs() changes the state of the
- # module, annotating structs with required information.
- for struct in self.GetStructs():
- self.Write(self.GenerateStructSource(struct),
+ for struct in self.module.structs:
+ self.Write(self._GenerateStructSource(struct),
'%s.java' % GetNameForElement(struct))
for union in self.module.unions:
- self.Write(self.GenerateUnionSource(union),
+ self.Write(self._GenerateUnionSource(union),
'%s.java' % GetNameForElement(union))
for enum in self.module.enums:
- self.Write(self.GenerateEnumSource(enum),
+ self.Write(self._GenerateEnumSource(enum),
'%s.java' % GetNameForElement(enum))
- for interface in self.GetInterfaces():
- self.Write(self.GenerateInterfaceSource(interface),
+ for interface in self.module.interfaces:
+ self.Write(self._GenerateInterfaceSource(interface),
'%s.java' % GetNameForElement(interface))
- self.Write(self.GenerateInterfaceInternalSource(interface),
+ self.Write(self._GenerateInterfaceInternalSource(interface),
'%s_Internal.java' % GetNameForElement(interface))
if self.module.constants:
- self.Write(self.GenerateConstantsSource(self.module),
+ self.Write(self._GenerateConstantsSource(self.module),
'%s.java' % GetConstantsMainEntityName(self.module))
def GenerateFiles(self, unparsed_args):
@@ -518,6 +524,8 @@ class Generator(generator.Generator):
if self.variant:
raise Exception("Variants not supported in Java bindings.")
+ self.module.Stylize(generator.Stylizer())
+
parser = argparse.ArgumentParser()
parser.add_argument('--java_output_directory', dest='java_output_directory')
args = parser.parse_args(unparsed_args)
@@ -525,17 +533,17 @@ class Generator(generator.Generator):
# Generate the java files in a temporary directory and place a single
# srcjar in the output directory.
- basename = self.MatchMojomFilePath("%s.srcjar" % self.module.name)
+ basename = "%s.srcjar" % self.module.path
zip_filename = os.path.join(self.output_dir, basename)
with TempDir() as temp_java_root:
self.output_dir = os.path.join(temp_java_root, package_path)
- self.DoGenerateFiles();
+ self._DoGenerateFiles();
build_utils.ZipDir(zip_filename, temp_java_root)
if args.java_output_directory:
# If requested, generate the java files directly into indicated directory.
self.output_dir = os.path.join(args.java_output_directory, package_path)
- self.DoGenerateFiles();
+ self._DoGenerateFiles();
def GetJinjaParameters(self):
return {
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py
index ab9635ee30..e403df6167 100644
--- a/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -8,6 +8,7 @@ import mojom.generate.generator as generator
import mojom.generate.module as mojom
import mojom.generate.pack as pack
import os
+import urllib
from mojom.generate.template_expander import UseJinja
_kind_to_javascript_default_value = {
@@ -36,54 +37,6 @@ _kind_to_javascript_default_value = {
mojom.NULLABLE_STRING: "null"
}
-
-def JavaScriptType(kind):
- name = []
- if kind.imported_from:
- name.append(kind.imported_from["unique_name"])
- if kind.parent_kind:
- name.append(kind.parent_kind.name)
- name.append(kind.name)
- return ".".join(name)
-
-
-def JavaScriptDefaultValue(field):
- if field.default:
- if mojom.IsStructKind(field.kind):
- 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 mojom.IsStructKind(field.kind):
- return "null"
- if mojom.IsUnionKind(field.kind):
- return "null"
- if mojom.IsArrayKind(field.kind):
- return "null"
- if mojom.IsMapKind(field.kind):
- return "null"
- if mojom.IsInterfaceKind(field.kind):
- return "new %sPtr()" % JavaScriptType(field.kind)
- if mojom.IsInterfaceRequestKind(field.kind):
- return "new bindings.InterfaceRequest()"
- if mojom.IsAssociatedKind(field.kind):
- return "null"
- if mojom.IsEnumKind(field.kind):
- return "0"
- raise Exception("No valid default: %s" % field)
-
-
-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",
@@ -110,105 +63,118 @@ _kind_to_codec_type = {
mojom.NULLABLE_STRING: "codec.NullableString",
}
+_kind_to_closure_type = {
+ mojom.BOOL: "boolean",
+ mojom.INT8: "number",
+ mojom.UINT8: "number",
+ mojom.INT16: "number",
+ mojom.UINT16: "number",
+ mojom.INT32: "number",
+ mojom.UINT32: "number",
+ mojom.FLOAT: "number",
+ mojom.INT64: "number",
+ mojom.UINT64: "number",
+ mojom.DOUBLE: "number",
+ mojom.STRING: "string",
+ mojom.NULLABLE_STRING: "string",
+ mojom.HANDLE: "mojo.MojoHandle",
+ mojom.DCPIPE: "mojo.MojoHandle",
+ mojom.DPPIPE: "mojo.MojoHandle",
+ mojom.MSGPIPE: "mojo.MojoHandle",
+ mojom.SHAREDBUFFER: "mojo.MojoHandle",
+ mojom.NULLABLE_HANDLE: "mojo.MojoHandle",
+ mojom.NULLABLE_DCPIPE: "mojo.MojoHandle",
+ mojom.NULLABLE_DPPIPE: "mojo.MojoHandle",
+ mojom.NULLABLE_MSGPIPE: "mojo.MojoHandle",
+ mojom.NULLABLE_SHAREDBUFFER: "mojo.MojoHandle",
+}
-def CodecType(kind):
- if kind in mojom.PRIMITIVES:
- return _kind_to_codec_type[kind]
- if mojom.IsStructKind(kind):
- pointer_type = "NullablePointerTo" if mojom.IsNullableKind(kind) \
- else "PointerTo"
- return "new codec.%s(%s)" % (pointer_type, JavaScriptType(kind))
- if mojom.IsUnionKind(kind):
- return JavaScriptType(kind)
- if mojom.IsArrayKind(kind):
- array_type = "NullableArrayOf" if mojom.IsNullableKind(kind) else "ArrayOf"
- array_length = "" if kind.length is None else ", %d" % kind.length
- element_type = ElementCodecType(kind.kind)
- return "new codec.%s(%s%s)" % (array_type, element_type, array_length)
- if mojom.IsInterfaceKind(kind):
- return "new codec.%s(%sPtr)" % (
- "NullableInterface" if mojom.IsNullableKind(kind) else "Interface",
- JavaScriptType(kind))
- if mojom.IsInterfaceRequestKind(kind):
- return "codec.%s" % (
- "NullableInterfaceRequest" if mojom.IsNullableKind(kind)
- else "InterfaceRequest")
- if mojom.IsAssociatedInterfaceKind(kind):
- return "codec.AssociatedInterfaceNotSupported"
- if mojom.IsAssociatedInterfaceRequestKind(kind):
- return "codec.AssociatedInterfaceRequestNotSupported"
- if mojom.IsEnumKind(kind):
- return "new codec.Enum(%s)" % JavaScriptType(kind)
- if mojom.IsMapKind(kind):
- map_type = "NullableMapOf" if mojom.IsNullableKind(kind) else "MapOf"
- key_type = ElementCodecType(kind.key_kind)
- value_type = ElementCodecType(kind.value_kind)
- return "new codec.%s(%s, %s)" % (map_type, key_type, value_type)
- raise Exception("No codec type for %s" % kind)
-
-
-def ElementCodecType(kind):
- return "codec.PackedBool" if mojom.IsBoolKind(kind) else CodecType(kind)
-
-
-def JavaScriptDecodeSnippet(kind):
- if (kind in mojom.PRIMITIVES or mojom.IsUnionKind(kind) or
- mojom.IsAnyInterfaceKind(kind)):
- return "decodeStruct(%s)" % CodecType(kind)
- if mojom.IsStructKind(kind):
- return "decodeStructPointer(%s)" % JavaScriptType(kind)
- if mojom.IsMapKind(kind):
- return "decodeMapPointer(%s, %s)" % \
- (ElementCodecType(kind.key_kind), ElementCodecType(kind.value_kind))
- if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind):
- return "decodeArrayPointer(codec.PackedBool)"
- if mojom.IsArrayKind(kind):
- return "decodeArrayPointer(%s)" % CodecType(kind.kind)
- if mojom.IsUnionKind(kind):
- return "decodeUnion(%s)" % CodecType(kind)
- if mojom.IsEnumKind(kind):
- return JavaScriptDecodeSnippet(mojom.INT32)
- raise Exception("No decode snippet for %s" % kind)
-
-
-def JavaScriptEncodeSnippet(kind):
- if (kind in mojom.PRIMITIVES or mojom.IsUnionKind(kind) or
- mojom.IsAnyInterfaceKind(kind)):
- return "encodeStruct(%s, " % CodecType(kind)
- if mojom.IsUnionKind(kind):
- return "encodeStruct(%s, " % JavaScriptType(kind)
- if mojom.IsStructKind(kind):
- return "encodeStructPointer(%s, " % JavaScriptType(kind)
- if mojom.IsMapKind(kind):
- return "encodeMapPointer(%s, %s, " % \
- (ElementCodecType(kind.key_kind), ElementCodecType(kind.value_kind))
- if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind):
- return "encodeArrayPointer(codec.PackedBool, ";
- if mojom.IsArrayKind(kind):
- return "encodeArrayPointer(%s, " % CodecType(kind.kind)
- if mojom.IsEnumKind(kind):
- return JavaScriptEncodeSnippet(mojom.INT32)
- raise Exception("No encode snippet for %s" % kind)
-
-
-def JavaScriptUnionDecodeSnippet(kind):
- if mojom.IsUnionKind(kind):
- return "decodeStructPointer(%s)" % JavaScriptType(kind)
- return JavaScriptDecodeSnippet(kind)
-
-
-def JavaScriptUnionEncodeSnippet(kind):
- if mojom.IsUnionKind(kind):
- return "encodeStructPointer(%s, " % JavaScriptType(kind)
- return JavaScriptEncodeSnippet(kind)
+_js_reserved_keywords = [
+ 'arguments',
+ 'await',
+ 'break'
+ 'case',
+ 'catch',
+ 'class',
+ 'const',
+ 'continue',
+ 'debugger',
+ 'default',
+ 'delete',
+ 'do',
+ 'else',
+ 'enum',
+ 'export',
+ 'extends',
+ 'finally',
+ 'for',
+ 'function',
+ 'if',
+ 'implements',
+ 'import',
+ 'in',
+ 'instanceof',
+ 'interface',
+ 'let',
+ 'new',
+ 'package',
+ 'private',
+ 'protected',
+ 'public',
+ 'return',
+ 'static',
+ 'super',
+ 'switch',
+ 'this',
+ 'throw',
+ 'try',
+ 'typeof',
+ 'var',
+ 'void',
+ 'while',
+ 'with',
+ 'yield',
+]
+
+_primitive_kind_to_fuzz_type = {
+ mojom.BOOL: "Bool",
+ mojom.INT8: "Int8",
+ mojom.UINT8: "Uint8",
+ mojom.INT16: "Int16",
+ mojom.UINT16: "Uint16",
+ mojom.INT32: "Int32",
+ mojom.UINT32: "Uint32",
+ mojom.FLOAT: "Float",
+ mojom.INT64: "Int64",
+ mojom.UINT64: "Uint64",
+ mojom.DOUBLE: "Double",
+ mojom.STRING: "String",
+ mojom.NULLABLE_STRING: "String",
+ mojom.HANDLE: "Handle",
+ mojom.DCPIPE: "DataPipeConsumer",
+ mojom.DPPIPE: "DataPipeProducer",
+ mojom.MSGPIPE: "MessagePipe",
+ mojom.SHAREDBUFFER: "SharedBuffer",
+ mojom.NULLABLE_HANDLE: "Handle",
+ mojom.NULLABLE_DCPIPE: "DataPipeConsumer",
+ mojom.NULLABLE_DPPIPE: "DataPipeProducer",
+ mojom.NULLABLE_MSGPIPE: "MessagePipe",
+ mojom.NULLABLE_SHAREDBUFFER: "SharedBuffer",
+}
-def JavaScriptFieldOffset(packed_field):
- return "offset + codec.kStructHeaderSize + %s" % packed_field.offset
+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
-def JavaScriptNullableParam(field):
- return "true" if mojom.IsNullableKind(field.kind) else "false"
+def JavaScriptFieldOffset(packed_field):
+ return "offset + codec.kStructHeaderSize + %s" % packed_field.offset
def GetArrayExpectedDimensionSizes(kind):
@@ -222,185 +188,134 @@ def GetArrayExpectedDimensionSizes(kind):
return expected_dimension_sizes
-def JavaScriptValidateArrayParams(field):
- nullable = JavaScriptNullableParam(field)
- element_kind = field.kind.kind
- element_size = pack.PackedField.GetSizeForKind(element_kind)
- expected_dimension_sizes = GetArrayExpectedDimensionSizes(
- field.kind)
- element_type = ElementCodecType(element_kind)
- return "%s, %s, %s, %s, 0" % \
- (element_size, element_type, nullable,
- expected_dimension_sizes)
-
-
-def JavaScriptValidateEnumParams(field):
- return JavaScriptType(field.kind)
-
-def JavaScriptValidateStructParams(field):
- nullable = JavaScriptNullableParam(field)
- struct_type = JavaScriptType(field.kind)
- return "%s, %s" % (struct_type, nullable)
-
-def JavaScriptValidateUnionParams(field):
- nullable = JavaScriptNullableParam(field)
- union_type = JavaScriptType(field.kind)
- return "%s, %s" % (union_type, nullable)
-
-def JavaScriptValidateMapParams(field):
- nullable = JavaScriptNullableParam(field)
- keys_type = ElementCodecType(field.kind.key_kind)
- values_kind = field.kind.value_kind;
- values_type = ElementCodecType(values_kind)
- values_nullable = "true" if mojom.IsNullableKind(values_kind) else "false"
- return "%s, %s, %s, %s" % \
- (nullable, keys_type, values_type, values_nullable)
-
-
-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)
-
- if isinstance(token, mojom.BuiltinValue):
- if token.value == "double.INFINITY" or token.value == "float.INFINITY":
- return "Infinity";
- if token.value == "double.NEGATIVE_INFINITY" or \
- token.value == "float.NEGATIVE_INFINITY":
- return "-Infinity";
- if token.value == "double.NAN" or token.value == "float.NAN":
- return "NaN";
-
- return token
-
-
-def ExpressionToText(value):
- return TranslateConstants(value)
-
-def IsArrayPointerField(field):
- return mojom.IsArrayKind(field.kind)
-
-def IsEnumField(field):
- return mojom.IsEnumKind(field.kind)
-
-def IsStringPointerField(field):
- return mojom.IsStringKind(field.kind)
+def GetRelativeUrl(module, base_module):
+ return urllib.pathname2url(
+ os.path.relpath(module.path, os.path.dirname(base_module.path)))
-def IsStructPointerField(field):
- return mojom.IsStructKind(field.kind)
-def IsMapPointerField(field):
- return mojom.IsMapKind(field.kind)
+class JavaScriptStylizer(generator.Stylizer):
+ def StylizeConstant(self, mojom_name):
+ return mojom_name
-def IsHandleField(field):
- return mojom.IsAnyHandleKind(field.kind)
+ def StylizeField(self, mojom_name):
+ return generator.ToCamel(mojom_name, lower_initial=True)
-def IsInterfaceField(field):
- return mojom.IsInterfaceKind(field.kind)
+ def StylizeStruct(self, mojom_name):
+ return mojom_name
-def IsInterfaceRequestField(field):
- return mojom.IsInterfaceRequestKind(field.kind)
+ def StylizeUnion(self, mojom_name):
+ return mojom_name
-def IsUnionField(field):
- return mojom.IsUnionKind(field.kind)
+ def StylizeParameter(self, mojom_name):
+ return generator.ToCamel(mojom_name, lower_initial=True)
-def IsBoolField(field):
- return mojom.IsBoolKind(field.kind)
+ def StylizeMethod(self, mojom_name):
+ return generator.ToCamel(mojom_name, lower_initial=True)
-def IsObjectField(field):
- return mojom.IsObjectKind(field.kind)
+ def StylizeEnumField(self, mojom_name):
+ return mojom_name
-def IsAnyHandleOrInterfaceField(field):
- return mojom.IsAnyHandleOrInterfaceKind(field.kind)
+ def StylizeEnum(self, mojom_name):
+ return mojom_name
-def IsEnumField(field):
- return mojom.IsEnumKind(field.kind)
-
-def GetRelativePath(module, base_module):
- return os.path.relpath(module.path, os.path.dirname(base_module.path))
+ def StylizeModule(self, mojom_namespace):
+ return '.'.join(generator.ToCamel(word, lower_initial=True)
+ for word in mojom_namespace.split('.'))
class Generator(generator.Generator):
-
- js_filters = {
- "decode_snippet": JavaScriptDecodeSnippet,
- "default_value": JavaScriptDefaultValue,
- "encode_snippet": JavaScriptEncodeSnippet,
- "expression_to_text": ExpressionToText,
- "field_offset": JavaScriptFieldOffset,
- "has_callbacks": mojom.HasCallbacks,
- "is_any_handle_or_interface_field": IsAnyHandleOrInterfaceField,
- "is_array_pointer_field": IsArrayPointerField,
- "is_bool_field": IsBoolField,
- "is_enum_field": IsEnumField,
- "is_handle_field": IsHandleField,
- "is_interface_field": IsInterfaceField,
- "is_interface_request_field": IsInterfaceRequestField,
- "is_map_pointer_field": IsMapPointerField,
- "is_object_field": IsObjectField,
- "is_string_pointer_field": IsStringPointerField,
- "is_struct_pointer_field": IsStructPointerField,
- "is_union_field": IsUnionField,
- "js_type": JavaScriptType,
- "payload_size": JavaScriptPayloadSize,
- "get_relative_path": GetRelativePath,
- "stylize_method": generator.StudlyCapsToCamel,
- "union_decode_snippet": JavaScriptUnionDecodeSnippet,
- "union_encode_snippet": JavaScriptUnionEncodeSnippet,
- "validate_array_params": JavaScriptValidateArrayParams,
- "validate_enum_params": JavaScriptValidateEnumParams,
- "validate_map_params": JavaScriptValidateMapParams,
- "validate_nullable_params": JavaScriptNullableParam,
- "validate_struct_params": JavaScriptValidateStructParams,
- "validate_union_params": JavaScriptValidateUnionParams,
- }
-
- def GetParameters(self):
+ def _GetParameters(self):
return {
- "namespace": self.module.namespace,
- "imports": self.GetImports(),
- "kinds": self.module.kinds,
"enums": self.module.enums,
+ "imports": self.module.imports,
+ "interfaces": self.module.interfaces,
+ "kinds": self.module.kinds,
"module": self.module,
- "structs": self.GetStructs() + self.GetStructsFromMethods(),
- "unions": self.GetUnions(),
- "use_new_js_bindings": self.use_new_js_bindings,
- "interfaces": self.GetInterfaces(),
- "imported_interfaces": self.GetImportedInterfaces(),
+ "structs": self.module.structs + self._GetStructsFromMethods(),
+ "unions": self.module.unions,
+ "generate_fuzzing": self.generate_fuzzing,
}
@staticmethod
def GetTemplatePrefix():
return "js_templates"
- @classmethod
- def GetFilters(cls):
- return cls.js_filters
+ def GetFilters(self):
+ js_filters = {
+ "closure_type": self._ClosureType,
+ "decode_snippet": self._JavaScriptDecodeSnippet,
+ "default_value": self._JavaScriptDefaultValue,
+ "encode_snippet": self._JavaScriptEncodeSnippet,
+ "expression_to_text": self._ExpressionToText,
+ "field_offset": JavaScriptFieldOffset,
+ "get_relative_url": GetRelativeUrl,
+ "has_callbacks": mojom.HasCallbacks,
+ "is_any_handle_or_interface_kind": mojom.IsAnyHandleOrInterfaceKind,
+ "is_array_kind": mojom.IsArrayKind,
+ "is_associated_interface_kind": mojom.IsAssociatedInterfaceKind,
+ "is_associated_interface_request_kind":
+ mojom.IsAssociatedInterfaceRequestKind,
+ "is_bool_kind": mojom.IsBoolKind,
+ "is_enum_kind": mojom.IsEnumKind,
+ "is_any_handle_kind": mojom.IsAnyHandleKind,
+ "is_any_interface_kind": mojom.IsAnyInterfaceKind,
+ "is_interface_kind": mojom.IsInterfaceKind,
+ "is_interface_request_kind": mojom.IsInterfaceRequestKind,
+ "is_map_kind": mojom.IsMapKind,
+ "is_object_kind": mojom.IsObjectKind,
+ "is_reference_kind": mojom.IsReferenceKind,
+ "is_string_kind": mojom.IsStringKind,
+ "is_struct_kind": mojom.IsStructKind,
+ "is_union_kind": mojom.IsUnionKind,
+ "js_type": self._JavaScriptType,
+ "method_passes_associated_kinds": mojom.MethodPassesAssociatedKinds,
+ "namespace_declarations": self._NamespaceDeclarations,
+ "closure_type_with_nullability": self._ClosureTypeWithNullability,
+ "payload_size": JavaScriptPayloadSize,
+ "to_camel": generator.ToCamel,
+ "union_decode_snippet": self._JavaScriptUnionDecodeSnippet,
+ "union_encode_snippet": self._JavaScriptUnionEncodeSnippet,
+ "validate_array_params": self._JavaScriptValidateArrayParams,
+ "validate_enum_params": self._JavaScriptValidateEnumParams,
+ "validate_map_params": self._JavaScriptValidateMapParams,
+ "validate_nullable_params": self._JavaScriptNullableParam,
+ "validate_struct_params": self._JavaScriptValidateStructParams,
+ "validate_union_params": self._JavaScriptValidateUnionParams,
+ "sanitize_identifier": self._JavaScriptSanitizeIdentifier,
+ "contains_handles_or_interfaces": mojom.ContainsHandlesOrInterfaces,
+ "fuzz_handle_name": self._FuzzHandleName,
+ "is_primitive_kind": self._IsPrimitiveKind,
+ "primitive_to_fuzz_type": self._PrimitiveToFuzzType,
+ "to_js_boolean": self._ToJsBoolean,
+ }
+ return js_filters
@UseJinja("module.amd.tmpl")
- def GenerateAMDModule(self):
- return self.GetParameters()
+ def _GenerateAMDModule(self):
+ return self._GetParameters()
+
+ @UseJinja("externs/module.externs.tmpl")
+ def _GenerateExterns(self):
+ return self._GetParameters()
def GenerateFiles(self, args):
if self.variant:
raise Exception("Variants not supported in JavaScript bindings.")
- self.Write(self.GenerateAMDModule(),
- self.MatchMojomFilePath("%s.js" % self.module.name))
+ self.module.Stylize(JavaScriptStylizer())
- def GetImports(self):
+ # TODO(crbug.com/795977): Change the media router extension to not mess with
+ # the mojo namespace, so that namespaces such as "mojo.common.mojom" are not
+ # affected and we can remove this method.
+ self._SetUniqueNameForImports()
+
+ self.Write(self._GenerateAMDModule(), "%s.js" % self.module.path)
+ self.Write(self._GenerateExterns(), "%s.externs.js" % self.module.path)
+
+ def _SetUniqueNameForImports(self):
used_names = set()
for each_import in self.module.imports:
- simple_name = each_import["module_name"].split(".")[0]
+ simple_name = os.path.basename(each_import.path).split(".")[0]
# Since each import is assigned a variable in JS, they need to have unique
# names.
@@ -411,15 +326,287 @@ class Generator(generator.Generator):
unique_name = simple_name + str(counter)
used_names.add(unique_name)
- each_import["unique_name"] = unique_name + "$"
+ each_import.unique_name = unique_name + "$"
counter += 1
- return self.module.imports
- def GetImportedInterfaces(self):
- interface_to_import = {};
- for each_import in self.module.imports:
- for each_interface in each_import["module"].interfaces:
- name = each_interface.name
- interface_to_import[name] = each_import["unique_name"] + "." + name
- return interface_to_import;
+ def _ClosureType(self, kind):
+ if kind in mojom.PRIMITIVES:
+ return _kind_to_closure_type[kind]
+ if mojom.IsInterfaceKind(kind):
+ return kind.module.namespace + "." + kind.name + "Ptr"
+ if (mojom.IsStructKind(kind) or
+ mojom.IsEnumKind(kind)):
+ return kind.module.namespace + "." + kind.name
+ # TODO(calamity): Support unions properly.
+ if mojom.IsUnionKind(kind):
+ return "Object"
+ if mojom.IsArrayKind(kind):
+ return "Array<%s>" % self._ClosureType(kind.kind)
+ if mojom.IsMapKind(kind):
+ return "Map<%s, %s>" % (
+ self._ClosureType(kind.key_kind), self._ClosureType(kind.value_kind))
+ if mojom.IsInterfaceRequestKind(kind):
+ return "mojo.InterfaceRequest"
+ # TODO(calamity): Support associated interfaces properly.
+ if mojom.IsAssociatedInterfaceKind(kind):
+ return "mojo.AssociatedInterfacePtrInfo"
+ # TODO(calamity): Support associated interface requests properly.
+ if mojom.IsAssociatedInterfaceRequestKind(kind):
+ return "mojo.AssociatedInterfaceRequest"
+ # TODO(calamity): Support enums properly.
+
+ raise Exception("No valid closure type: %s" % kind)
+
+ def _ClosureTypeWithNullability(self, kind):
+ return ("" if mojom.IsNullableKind(kind) else "!") + self._ClosureType(kind)
+
+ def _NamespaceDeclarations(self, namespace):
+ pieces = namespace.split('.')
+ declarations = []
+ declaration = []
+ for p in pieces:
+ declaration.append(p)
+ declarations.append('.'.join(declaration))
+ return declarations
+
+ def _JavaScriptType(self, kind):
+ name = []
+ if kind.module and kind.module.path != self.module.path:
+ name.append(kind.module.unique_name)
+ if kind.parent_kind:
+ name.append(kind.parent_kind.name)
+ name.append(kind.name)
+ return ".".join(name)
+ def _JavaScriptDefaultValue(self, field):
+ if field.default:
+ if mojom.IsStructKind(field.kind):
+ assert field.default == "default"
+ return "new %s()" % self._JavaScriptType(field.kind)
+ return self._ExpressionToText(field.default)
+ if field.kind in mojom.PRIMITIVES:
+ return _kind_to_javascript_default_value[field.kind]
+ if mojom.IsStructKind(field.kind):
+ return "null"
+ if mojom.IsUnionKind(field.kind):
+ return "null"
+ if mojom.IsArrayKind(field.kind):
+ return "null"
+ if mojom.IsMapKind(field.kind):
+ return "null"
+ if mojom.IsInterfaceKind(field.kind):
+ return "new %sPtr()" % self._JavaScriptType(field.kind)
+ if mojom.IsInterfaceRequestKind(field.kind):
+ return "new bindings.InterfaceRequest()"
+ if mojom.IsAssociatedInterfaceKind(field.kind):
+ return "new associatedBindings.AssociatedInterfacePtrInfo()"
+ if mojom.IsAssociatedInterfaceRequestKind(field.kind):
+ return "new associatedBindings.AssociatedInterfaceRequest()"
+ if mojom.IsEnumKind(field.kind):
+ return "0"
+ raise Exception("No valid default: %s" % field)
+
+ def _CodecType(self, kind):
+ if kind in mojom.PRIMITIVES:
+ return _kind_to_codec_type[kind]
+ if mojom.IsStructKind(kind):
+ pointer_type = "NullablePointerTo" if mojom.IsNullableKind(kind) \
+ else "PointerTo"
+ return "new codec.%s(%s)" % (pointer_type, self._JavaScriptType(kind))
+ if mojom.IsUnionKind(kind):
+ return self._JavaScriptType(kind)
+ if mojom.IsArrayKind(kind):
+ array_type = ("NullableArrayOf" if mojom.IsNullableKind(kind)
+ else "ArrayOf")
+ array_length = "" if kind.length is None else ", %d" % kind.length
+ element_type = self._ElementCodecType(kind.kind)
+ return "new codec.%s(%s%s)" % (array_type, element_type, array_length)
+ if mojom.IsInterfaceKind(kind):
+ return "new codec.%s(%sPtr)" % (
+ "NullableInterface" if mojom.IsNullableKind(kind) else "Interface",
+ self._JavaScriptType(kind))
+ if mojom.IsInterfaceRequestKind(kind):
+ return "codec.%s" % (
+ "NullableInterfaceRequest" if mojom.IsNullableKind(kind)
+ else "InterfaceRequest")
+ if mojom.IsAssociatedInterfaceKind(kind):
+ return "codec.%s" % ("NullableAssociatedInterfacePtrInfo"
+ if mojom.IsNullableKind(kind) else "AssociatedInterfacePtrInfo")
+ if mojom.IsAssociatedInterfaceRequestKind(kind):
+ return "codec.%s" % ("NullableAssociatedInterfaceRequest"
+ if mojom.IsNullableKind(kind) else "AssociatedInterfaceRequest")
+ if mojom.IsEnumKind(kind):
+ return "new codec.Enum(%s)" % self._JavaScriptType(kind)
+ if mojom.IsMapKind(kind):
+ map_type = "NullableMapOf" if mojom.IsNullableKind(kind) else "MapOf"
+ key_type = self._ElementCodecType(kind.key_kind)
+ value_type = self._ElementCodecType(kind.value_kind)
+ return "new codec.%s(%s, %s)" % (map_type, key_type, value_type)
+ raise Exception("No codec type for %s" % kind)
+
+ def _ElementCodecType(self, kind):
+ return ("codec.PackedBool" if mojom.IsBoolKind(kind)
+ else self._CodecType(kind))
+
+ def _JavaScriptDecodeSnippet(self, kind):
+ if (kind in mojom.PRIMITIVES or mojom.IsUnionKind(kind) or
+ mojom.IsAnyInterfaceKind(kind)):
+ return "decodeStruct(%s)" % self._CodecType(kind)
+ if mojom.IsStructKind(kind):
+ return "decodeStructPointer(%s)" % self._JavaScriptType(kind)
+ if mojom.IsMapKind(kind):
+ return "decodeMapPointer(%s, %s)" % (
+ self._ElementCodecType(kind.key_kind),
+ self._ElementCodecType(kind.value_kind))
+ if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind):
+ return "decodeArrayPointer(codec.PackedBool)"
+ if mojom.IsArrayKind(kind):
+ return "decodeArrayPointer(%s)" % self._CodecType(kind.kind)
+ if mojom.IsUnionKind(kind):
+ return "decodeUnion(%s)" % self._CodecType(kind)
+ if mojom.IsEnumKind(kind):
+ return self._JavaScriptDecodeSnippet(mojom.INT32)
+ raise Exception("No decode snippet for %s" % kind)
+
+ def _JavaScriptEncodeSnippet(self, kind):
+ if (kind in mojom.PRIMITIVES or mojom.IsUnionKind(kind) or
+ mojom.IsAnyInterfaceKind(kind)):
+ return "encodeStruct(%s, " % self._CodecType(kind)
+ if mojom.IsUnionKind(kind):
+ return "encodeStruct(%s, " % self._JavaScriptType(kind)
+ if mojom.IsStructKind(kind):
+ return "encodeStructPointer(%s, " % self._JavaScriptType(kind)
+ if mojom.IsMapKind(kind):
+ return "encodeMapPointer(%s, %s, " % (
+ self._ElementCodecType(kind.key_kind),
+ self._ElementCodecType(kind.value_kind))
+ if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind):
+ return "encodeArrayPointer(codec.PackedBool, ";
+ if mojom.IsArrayKind(kind):
+ return "encodeArrayPointer(%s, " % self._CodecType(kind.kind)
+ if mojom.IsEnumKind(kind):
+ return self._JavaScriptEncodeSnippet(mojom.INT32)
+ raise Exception("No encode snippet for %s" % kind)
+
+ def _JavaScriptUnionDecodeSnippet(self, kind):
+ if mojom.IsUnionKind(kind):
+ return "decodeStructPointer(%s)" % self._JavaScriptType(kind)
+ return self._JavaScriptDecodeSnippet(kind)
+
+ def _JavaScriptUnionEncodeSnippet(self, kind):
+ if mojom.IsUnionKind(kind):
+ return "encodeStructPointer(%s, " % self._JavaScriptType(kind)
+ return self._JavaScriptEncodeSnippet(kind)
+
+ def _JavaScriptNullableParam(self, field):
+ return "true" if mojom.IsNullableKind(field.kind) else "false"
+
+ def _JavaScriptValidateArrayParams(self, field):
+ nullable = self._JavaScriptNullableParam(field)
+ element_kind = field.kind.kind
+ element_size = pack.PackedField.GetSizeForKind(element_kind)
+ expected_dimension_sizes = GetArrayExpectedDimensionSizes(
+ field.kind)
+ element_type = self._ElementCodecType(element_kind)
+ return "%s, %s, %s, %s, 0" % \
+ (element_size, element_type, nullable,
+ expected_dimension_sizes)
+
+ def _JavaScriptValidateEnumParams(self, field):
+ return self._JavaScriptType(field.kind)
+
+ def _JavaScriptValidateStructParams(self, field):
+ nullable = self._JavaScriptNullableParam(field)
+ struct_type = self._JavaScriptType(field.kind)
+ return "%s, %s" % (struct_type, nullable)
+
+ def _JavaScriptValidateUnionParams(self, field):
+ nullable = self._JavaScriptNullableParam(field)
+ union_type = self._JavaScriptType(field.kind)
+ return "%s, %s" % (union_type, nullable)
+
+ def _JavaScriptValidateMapParams(self, field):
+ nullable = self._JavaScriptNullableParam(field)
+ keys_type = self._ElementCodecType(field.kind.key_kind)
+ values_kind = field.kind.value_kind;
+ values_type = self._ElementCodecType(values_kind)
+ values_nullable = "true" if mojom.IsNullableKind(values_kind) else "false"
+ return "%s, %s, %s, %s" % \
+ (nullable, keys_type, values_type, values_nullable)
+
+ def _JavaScriptSanitizeIdentifier(self, identifier):
+ if identifier in _js_reserved_keywords:
+ return identifier + '_'
+
+ return identifier
+
+ def _TranslateConstants(self, token):
+ if isinstance(token, (mojom.EnumValue, mojom.NamedValue)):
+ # Both variable and enum constants are constructed like:
+ # NamespaceUid.Struct[.Enum].CONSTANT_NAME
+ name = []
+ if token.module and token.module.path != self.module.path:
+ name.append(token.module.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)
+
+ if isinstance(token, mojom.BuiltinValue):
+ if token.value == "double.INFINITY" or token.value == "float.INFINITY":
+ return "Infinity";
+ if token.value == "double.NEGATIVE_INFINITY" or \
+ token.value == "float.NEGATIVE_INFINITY":
+ return "-Infinity";
+ if token.value == "double.NAN" or token.value == "float.NAN":
+ return "NaN";
+
+ return token
+
+ def _ExpressionToText(self, value):
+ return self._TranslateConstants(value)
+
+ def _GetStructsFromMethods(self):
+ result = []
+ for interface in self.module.interfaces:
+ for method in interface.methods:
+ result.append(method.param_struct)
+ if method.response_param_struct is not None:
+ result.append(method.response_param_struct)
+ return result
+
+ def _FuzzHandleName(self, kind):
+ if mojom.IsInterfaceRequestKind(kind):
+ return '{0}.{1}Request'.format(kind.kind.module.namespace,
+ kind.kind.name)
+ elif mojom.IsInterfaceKind(kind):
+ return '{0}.{1}Ptr'.format(kind.module.namespace,
+ kind.name)
+ elif mojom.IsAssociatedInterfaceRequestKind(kind):
+ return '{0}.{1}AssociatedRequest'.format(kind.kind.module.namespace,
+ kind.kind.name)
+ elif mojom.IsAssociatedInterfaceKind(kind):
+ return '{0}.{1}AssociatedPtr'.format(kind.kind.module.namespace,
+ kind.kind.name)
+ elif mojom.IsSharedBufferKind(kind):
+ return 'handle<shared_buffer>'
+ elif mojom.IsDataPipeConsumerKind(kind):
+ return 'handle<data_pipe_consumer>'
+ elif mojom.IsDataPipeProducerKind(kind):
+ return 'handle<data_pipe_producer>'
+ elif mojom.IsMessagePipeKind(kind):
+ return 'handle<message_pipe>'
+
+ def _ToJsBoolean(self, value):
+ if value:
+ return 'true'
+
+ return 'false'
+
+ def _IsPrimitiveKind(self, kind):
+ return kind in mojom.PRIMITIVES
+
+ def _PrimitiveToFuzzType(self, kind):
+ return _primitive_kind_to_fuzz_type[kind]
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index 4a244fb5b1..3329631470 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -2,6 +2,19 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/jumbo.gni")
+
+# TODO(rockot): Maybe we can factor these dependencies out of //mojo. They're
+# used to conditionally enable message ID scrambling in a way which is
+# consistent across toolchains and which is affected by branded vs non-branded
+# Chrome builds. Ideally we could create some generic knobs here that could be
+# flipped elsewhere though.
+import("//build/config/chrome_build.gni")
+import("//build/config/nacl/config.gni")
+import("//components/nacl/features.gni")
+import("//third_party/jinja2/jinja2.gni")
+import("//tools/ipc_fuzzer/ipc_fuzzer.gni")
+
declare_args() {
# Indicates whether typemapping should be supported in this build
# configuration. This may be disabled when building external projects which
@@ -12,8 +25,32 @@ declare_args() {
# with typemapping disabled, so it is never valid to set this to |false| in
# any Chromium build configuration.
enable_mojom_typemapping = true
+
+ # Controls message ID scrambling behavior. If |true|, message IDs are
+ # scrambled (i.e. randomized based on the contents of //chrome/VERSION) on
+ # non-Chrome OS desktop platforms. Set to |false| to disable message ID
+ # scrambling on all platforms.
+ enable_mojom_message_id_scrambling = true
}
+# NOTE: We would like to avoid scrambling message IDs where it doesn't add
+# value, so we limit the behavior to desktop builds for now. There is some
+# redundancy in the conditions here, but it is tolerated for clarity:
+# We're explicit about Mac, Windows, and Linux desktop support, but it's
+# also necessary to ensure that bindings in alternate toolchains (e.g.
+# NaCl IRT) are always consistent with the default toolchain; for that
+# reason we always enable scrambling within NaCl toolchains when possible,
+# as well as within the default toolchain when NaCl is enabled.
+#
+# Finally, because we *cannot* enable scrambling on Chrome OS (it would break
+# ARC) we have to explicitly opt out there even when NaCl is enabled (and
+# consequently also when building for NaCl toolchains.) For this reason we
+# check |target_os| explicitly, as it's consistent across all toolchains.
+enable_scrambled_message_ids =
+ enable_mojom_message_id_scrambling &&
+ (is_mac || is_win || (is_linux && !is_chromeos) ||
+ ((enable_nacl || is_nacl || is_nacl_nonsfi) && target_os != "chromeos"))
+
mojom_generator_root = "//mojo/public/tools/bindings"
mojom_generator_script = "$mojom_generator_root/mojom_bindings_generator.py"
mojom_generator_sources = [
@@ -36,6 +73,43 @@ mojom_generator_sources = [
"$mojom_generator_script",
]
+if (enable_scrambled_message_ids) {
+ declare_args() {
+ # The path to a file whose contents can be used as the basis for a message
+ # ID scrambling salt.
+ mojom_message_id_salt_path = "//chrome/VERSION"
+
+ # The path to a file whose contents will be concatenated to the contents of
+ # the file at |mojom_message_id_salt_path| to form a complete salt for
+ # message ID scrambling. May be the empty string, in which case the contents
+ # of the above file alone are used as the complete salt.
+ if (is_chrome_branded) {
+ mojom_message_id_salt_suffix_path =
+ "//mojo/internal/chrome-message-id-salt-suffix"
+ } else {
+ mojom_message_id_salt_suffix_path = ""
+ }
+ }
+
+ assert(mojom_message_id_salt_path != "")
+ message_scrambling_args = [
+ "--scrambled_message_id_salt_path",
+ rebase_path(mojom_message_id_salt_path, root_build_dir),
+ ]
+ message_scrambling_inputs = [ mojom_message_id_salt_path ]
+
+ if (mojom_message_id_salt_suffix_path != "") {
+ message_scrambling_args += [
+ "--scrambled_message_id_salt_path",
+ rebase_path(mojom_message_id_salt_suffix_path, root_build_dir),
+ ]
+ message_scrambling_inputs += [ mojom_message_id_salt_suffix_path ]
+ }
+} else {
+ message_scrambling_args = []
+ message_scrambling_inputs = []
+}
+
if (enable_mojom_typemapping) {
if (!is_ios) {
_bindings_configuration_files = [
@@ -58,23 +132,17 @@ if (enable_mojom_typemapping) {
_typemap_config = typemap.config
read_file(_typemap_config.mojom, "")
}
- if (is_mac && defined(configuration.typemaps_mac)) {
- foreach(typemap, configuration.typemaps_mac) {
- _typemap_config = {
- }
- _typemap_config = typemap.config
- read_file(_typemap_config.mojom, "")
- }
- }
}
} else {
_bindings_configuration_files = []
_bindings_configurations = [
{
typemaps = []
+ component_macro_suffix = ""
},
{
variant = "blink"
+ component_macro_suffix = "_BLINK"
for_blink = true
typemaps = []
},
@@ -89,8 +157,7 @@ if (enable_mojom_typemapping) {
# is the target name):
#
# foo
-# C++ and Javascript bindings. Other mojom targets should also depend on
-# this target.
+# C++ bindings.
#
# foo_blink
# C++ bindings using Blink standard types.
@@ -98,6 +165,12 @@ if (enable_mojom_typemapping) {
# foo_java
# Java bindings.
#
+# foo_js
+# JavaScript bindings; used as compile-time dependency.
+#
+# foo_js_data_deps
+# JavaScript bindings; used as run-time dependency.
+#
# Parameters:
#
# sources (optional if one of the deps sets listed below is present)
@@ -126,7 +199,7 @@ if (enable_mojom_typemapping) {
# use_once_callback (optional)
# If set to true, generated classes will use base::OnceCallback instead of
# base::RepeatingCallback.
-# Default value is false.
+# Default value is true.
# TODO(dcheng):
# - Convert everything to use OnceCallback.
# - Remove support for the old mode.
@@ -134,17 +207,63 @@ if (enable_mojom_typemapping) {
# cpp_only (optional)
# If set to true, only the C++ bindings targets will be generated.
#
-# use_new_js_bindings (optional)
-# If set to true, the generated JS code will use the new module loading
-# approach and the core API exposed by Web IDL.
+# support_lazy_serialization (optional)
+# If set to |true|, generated C++ bindings will effectively prefer to
+# transmit messages in an unserialized form when going between endpoints
+# in the same process. This avoids the runtime cost of serialization,
+# deserialization, and validation logic at the expensive of increased
+# code size. Defaults to |false|.
+#
+# disable_variants (optional)
+# If |true|, no variant sources will be generated for the target. Defaults
+# to |false|.
+#
+# disallow_native_types (optional)
+# If set to |true|, mojoms in this target may not apply the [Native]
+# attribute to struct or enum declarations. This avoids emitting code
+# which depends on legacy IPC serialization. Default is |false|, meaning
+# [Native] types are allowed.
#
-# TODO(yzshen): Switch all existing users to use_new_js_bindings=true and
-# remove the old mode.
+# disallow_interfaces (optional)
+# If set to |true|, mojoms in this target may not define interfaces.
+# Generates bindings with a smaller set of dependencies. Defaults to
+# |false|.
+#
+# scramble_message_ids (optional)
+# If set to |true| (the default), generated mojom interfaces will use
+# scrambled ordinal identifiers in encoded messages.
+#
+# component_output_prefix (optional)
+# The prefix to use for the output_name of any component library emitted
+# for generated C++ bindings. If this is omitted, C++ bindings targets are
+# emitted as source_sets instead. Because this controls the name of the
+# output shared library binary in the root output directory, it must be
+# unique across the entire build configuration.
+#
+# This is required if |component_macro_prefix| is specified.
+#
+# component_macro_prefix (optional)
+# This specifies a macro prefix to use for component export macros and
+# should therefore be globally unique in the project. For example if this
+# is "FOO_BAR", then the generated C++ sources will be built with
+# IS_FOO_BAR_{suffix}_IMPL defined, and the generated public headers will
+# annotate public symbol definitions with
+# COMPONENT_EXPORT(FOO_BAR_{suffix}). "suffix" in this case depends on
+# which internal subtarget is generating the code (e.g. "SHARED", or a
+# variant name like "BLINK").
+#
+# enabled_features (optional)
+# Definitions in a mojom file can be guarded by an EnableIf attribute. If
+# the value specified by the attribute does not match any items in the
+# list of enabled_features, the definition will be disabled, with no code
+# emitted for it.
#
# The following parameters are used to support the component build. They are
# needed so that bindings which are linked with a component can use the same
# export settings for classes. The first three are for the chromium variant, and
-# the last three are for the blink variant.
+# the last three are for the blink variant. These parameters are mutually
+# exclusive to |component_macro_prefix|, but |component_output_prefix| may still
+# be used to uniqueify the generated invariant (i.e. shared) output component.
# export_class_attribute (optional)
# The attribute to add to the class declaration. e.g. "CONTENT_EXPORT"
# export_define (optional)
@@ -170,16 +289,23 @@ if (enable_mojom_typemapping) {
# overridden_deps_blink (optional)
# component_deps_blink (optional)
# These two parameters are the blink variants of the previous two.
+#
+# check_includes_blink (optional)
+# Overrides the check_includes variable for the blink variant.
+# If check_includes_blink is not defined, the check_includes variable
+# retains its original value.
template("mojom") {
assert(
defined(invoker.sources) || defined(invoker.deps) ||
defined(invoker.public_deps),
"\"sources\" or \"deps\" must be defined for the $target_name template.")
+
if (defined(invoker.export_class_attribute) ||
defined(invoker.export_define) || defined(invoker.export_header)) {
assert(defined(invoker.export_class_attribute))
assert(defined(invoker.export_define))
assert(defined(invoker.export_header))
+ assert(!defined(invoker.component_macro_prefix))
}
if (defined(invoker.export_class_attribute_blink) ||
defined(invoker.export_define_blink) ||
@@ -187,6 +313,7 @@ template("mojom") {
assert(defined(invoker.export_class_attribute_blink))
assert(defined(invoker.export_define_blink))
assert(defined(invoker.export_header_blink))
+ assert(!defined(invoker.component_macro_prefix))
}
if (defined(invoker.overridden_deps) || defined(invoker.component_deps)) {
assert(defined(invoker.overridden_deps))
@@ -199,6 +326,11 @@ template("mojom") {
assert(defined(invoker.component_deps_blink))
}
+ require_full_cpp_deps =
+ !defined(invoker.disallow_native_types) ||
+ !invoker.disallow_native_types || !defined(invoker.disallow_interfaces) ||
+ !invoker.disallow_interfaces
+
all_deps = []
if (defined(invoker.deps)) {
all_deps += invoker.deps
@@ -207,6 +339,10 @@ template("mojom") {
all_deps += invoker.public_deps
}
+ if (defined(invoker.component_macro_prefix)) {
+ assert(defined(invoker.component_output_prefix))
+ }
+
group("${target_name}__is_mojom") {
}
@@ -221,22 +357,162 @@ template("mojom") {
}
}
+ target_sources_list = "$target_gen_dir/$target_name.sources_list"
+ sources_list = []
+ if (defined(invoker.sources)) {
+ sources_list = invoker.sources
+ }
+ write_file(target_sources_list, sources_list)
+
+ # a target implicitly depends on its own sources
+ deps_sources = [ rebase_path(target_sources_list, root_build_dir) ]
+ foreach(d, all_deps) {
+ dep_dir = get_label_info("$d", "target_gen_dir")
+ dep_short_name = get_label_info("$d", "name")
+ deps_sources +=
+ [ rebase_path("$dep_dir/$dep_short_name.sources_list", root_build_dir) ]
+ }
+
+ write_file("$target_gen_dir/$target_name.deps_sources_list", deps_sources)
+
+ if (defined(invoker.sources)) {
+ parser_target_name = "${target_name}__parser"
+ enabled_features = []
+ if (defined(invoker.enabled_features)) {
+ enabled_features += invoker.enabled_features
+ }
+ if (is_posix) {
+ enabled_features += [ "is_posix" ]
+ }
+ if (is_android) {
+ enabled_features += [ "is_android" ]
+ } else if (is_chromeos) {
+ enabled_features += [ "is_chromeos" ]
+ } else if (is_fuchsia) {
+ enabled_features += [ "is_fuchsia" ]
+ } else if (is_ios) {
+ enabled_features += [ "is_ios" ]
+ } else if (is_linux) {
+ enabled_features += [ "is_linux" ]
+ } else if (is_mac) {
+ enabled_features += [ "is_mac" ]
+ } else if (is_win) {
+ enabled_features += [ "is_win" ]
+ }
+
+ action(parser_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = invoker.sources
+ outputs = []
+ filelist = []
+ foreach(source, invoker.sources) {
+ filename = get_path_info("$source", "name")
+ dirname = get_path_info("$source", "gen_dir")
+ outputs += [ "$dirname/$filename.p" ]
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ }
+
+ response_file_contents = filelist
+
+ args = [
+ "parse",
+ "--filelist={{response_file_name}}",
+ "-o",
+ rebase_path(root_gen_dir, root_build_dir),
+ "-d",
+ rebase_path("//", root_build_dir),
+ ]
+ foreach(enabled_feature, enabled_features) {
+ args += [
+ "--enable_feature",
+ enabled_feature,
+ ]
+ }
+ }
+ }
+
+ parsed_target_name = "${target_name}__parsed"
+ group(parsed_target_name) {
+ public_deps = []
+ if (defined(invoker.sources)) {
+ public_deps += [ ":$parser_target_name" ]
+ }
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append the parsed
+ # suffix to get the mojom dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps += [ "${full_name}__parsed" ]
+ }
+ }
+
+ if (defined(invoker.sources)) {
+ verify_deps_target_names = []
+ if (!defined(invoker.skip_deps_check) || !invoker.skip_deps_check) {
+ verify_deps_target_name = "${target_name}__verify_deps"
+ verify_deps_target_names += [ ":$verify_deps_target_name" ]
+ source_file_name = target_name
+
+ action(verify_deps_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = invoker.sources
+ deps = [
+ ":$parsed_target_name",
+ ]
+ outputs = []
+ filelist = []
+ foreach(source, invoker.sources) {
+ filename = get_path_info("$source", "name")
+ dirname = get_path_info("$source", "gen_dir")
+ outputs += [ "$dirname/$filename.v" ]
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ }
+
+ response_file_contents = filelist
+
+ args = [
+ "verify",
+ "--filelist={{response_file_name}}",
+ "-f",
+ rebase_path("$target_gen_dir/$source_file_name.deps_sources_list",
+ root_build_dir),
+ "--gen_dir",
+ rebase_path(root_gen_dir, root_build_dir),
+ "--depth",
+ rebase_path("//", root_build_dir),
+ ]
+ }
+ }
+ }
+
+ generator_cpp_message_ids_target_name = "${target_name}__generate_message_ids"
+
# Generate code that is shared by different variants.
if (defined(invoker.sources)) {
common_generator_args = [
"--use_bundled_pylibs",
"generate",
- "{{source}}",
"-d",
rebase_path("//", root_build_dir),
"-I",
rebase_path("//", root_build_dir),
"-o",
- rebase_path(root_gen_dir),
+ rebase_path(root_gen_dir, root_build_dir),
"--bytecode_path",
- rebase_path("$root_gen_dir/mojo/public/tools/bindings"),
+ rebase_path("$root_gen_dir/mojo/public/tools/bindings", root_build_dir),
]
+ if (defined(invoker.disallow_native_types) &&
+ invoker.disallow_native_types) {
+ common_generator_args += [ "--disallow_native_types" ]
+ }
+
+ if (defined(invoker.disallow_interfaces) && invoker.disallow_interfaces) {
+ common_generator_args += [ "--disallow_interfaces" ]
+ }
+
if (defined(invoker.import_dirs)) {
foreach(import_dir, invoker.import_dirs) {
common_generator_args += [
@@ -246,39 +522,122 @@ template("mojom") {
}
}
+ if (defined(invoker.component_macro_prefix)) {
+ shared_component_export_macro =
+ "COMPONENT_EXPORT(${invoker.component_macro_prefix}_SHARED)"
+ shared_component_impl_macro =
+ "IS_${invoker.component_macro_prefix}_SHARED_IMPL"
+ shared_component_output_name = "${invoker.component_output_prefix}_shared"
+ } else if (defined(invoker.export_class_attribute_shared) ||
+ defined(invoker.export_class_attribute)) {
+ if (defined(invoker.export_class_attribute_shared)) {
+ assert(defined(invoker.export_header_shared))
+ shared_component_export_macro = invoker.export_class_attribute_shared
+ shared_component_impl_macro = invoker.export_define_shared
+ } else {
+ assert(!defined(invoker.export_header_shared))
+
+ # If no explicit shared attribute/define was provided by the invoker,
+ # we derive some reasonable settings frorm the default variant.
+ shared_component_export_macro = "COMPONENT_EXPORT(MOJOM_SHARED_" +
+ invoker.export_class_attribute + ")"
+ shared_component_impl_macro =
+ "IS_MOJOM_SHARED_" + invoker.export_class_attribute + "_IMPL"
+ }
+
+ if (defined(invoker.component_output_prefix)) {
+ shared_component_output_name =
+ "${invoker.component_output_prefix}_shared"
+ } else {
+ shared_component_output_name = "${target_name}_shared"
+ }
+ }
+
+ action(generator_cpp_message_ids_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = invoker.sources
+ deps = [
+ ":$parsed_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+ outputs = []
+ args = common_generator_args
+ filelist = []
+ foreach(source, invoker.sources) {
+ outputs += [ "$target_gen_dir/$source-shared-message-ids.h" ]
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ }
+
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "--generate_non_variant_code",
+ "--generate_message_ids",
+ "-g",
+ "c++",
+ ]
+
+ if (!defined(invoker.scramble_message_ids) ||
+ invoker.scramble_message_ids) {
+ inputs += message_scrambling_inputs
+ args += message_scrambling_args
+ }
+ }
+
generator_shared_cpp_outputs = [
"{{source_gen_dir}}/{{source_name_part}}.mojom-shared-internal.h",
"{{source_gen_dir}}/{{source_name_part}}.mojom-shared.cc",
"{{source_gen_dir}}/{{source_name_part}}.mojom-shared.h",
]
generator_shared_target_name = "${target_name}_shared__generator"
- action_foreach(generator_shared_target_name) {
+ action(generator_shared_target_name) {
script = mojom_generator_script
- inputs = mojom_generator_sources
+ inputs = mojom_generator_sources + jinja2_sources
sources = invoker.sources
deps = [
- "//mojo/public/tools/bindings:precompile_templates",
- ]
- outputs = generator_shared_cpp_outputs
+ ":$parsed_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ] + verify_deps_target_names
+
+ outputs = []
args = common_generator_args
+ filelist = []
+ foreach(source, invoker.sources) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ outputs += [
+ "$target_gen_dir/$source-shared-internal.h",
+ "$target_gen_dir/$source-shared.cc",
+ "$target_gen_dir/$source-shared.h",
+ ]
+ }
+
+ response_file_contents = filelist
+
args += [
+ "--filelist={{response_file_name}}",
"--generate_non_variant_code",
"-g",
"c++",
]
- depfile = "{{source_gen_dir}}/${generator_shared_target_name}_{{source_name_part}}.d"
- args += [
- "--depfile",
- depfile,
- "--depfile_target",
- "{{source_gen_dir}}/{{source_name_part}}.mojom-shared-internal.h",
- ]
+
+ if (defined(shared_component_export_macro)) {
+ args += [
+ "--export_attribute",
+ shared_component_export_macro,
+ "--export_header",
+ "base/component_export.h",
+ ]
+ }
+ }
+ } else {
+ group(generator_cpp_message_ids_target_name) {
}
}
- shared_cpp_sources_suffix = "shared_cpp_sources"
- shared_cpp_sources_target_name = "${target_name}_${shared_cpp_sources_suffix}"
- source_set(shared_cpp_sources_target_name) {
+ shared_cpp_sources_target_name = "${target_name}_shared_cpp_sources"
+ jumbo_source_set(shared_cpp_sources_target_name) {
if (defined(invoker.testonly)) {
testonly = invoker.testonly
}
@@ -288,18 +647,58 @@ template("mojom") {
process_file_template(invoker.sources, generator_shared_cpp_outputs)
deps += [ ":$generator_shared_target_name" ]
}
- public_deps = []
+ if (require_full_cpp_deps) {
+ public_deps = [
+ "//mojo/public/cpp/bindings",
+ ]
+ } else {
+ public_deps = [
+ "//mojo/public/cpp/bindings:bindings_base",
+ ]
+ }
foreach(d, all_deps) {
# Resolve the name, so that a target //mojo/something becomes
# //mojo/something:something and we can append shared_cpp_sources_suffix
# to get the cpp dependency name.
full_name = get_label_info("$d", "label_no_toolchain")
- public_deps += [ "${full_name}_${shared_cpp_sources_suffix}" ]
+ public_deps += [ "${full_name}_shared" ]
+ }
+ if (defined(shared_component_impl_macro)) {
+ defines = [ shared_component_impl_macro ]
+ }
+ }
+
+ shared_cpp_library_target_name = "${target_name}_shared"
+ if (defined(shared_component_output_name)) {
+ component(shared_cpp_library_target_name) {
+ if (defined(invoker.testonly)) {
+ testonly = invoker.testonly
+ }
+ output_name = "$shared_component_output_name"
+ public_deps = [
+ ":$shared_cpp_sources_target_name",
+ ]
+ }
+ } else {
+ group(shared_cpp_library_target_name) {
+ if (defined(invoker.testonly)) {
+ testonly = invoker.testonly
+ }
+ public_deps = [
+ ":$shared_cpp_sources_target_name",
+ ]
}
}
# Generate code for variants.
- foreach(bindings_configuration, _bindings_configurations) {
+ if (!defined(invoker.disable_variants) || !invoker.disable_variants) {
+ enabled_configurations = _bindings_configurations
+ } else {
+ first_config = _bindings_configurations[0]
+ assert(!defined(first_config.variant))
+ enabled_configurations = [ first_config ]
+ }
+ foreach(bindings_configuration, enabled_configurations) {
cpp_only = false
if (defined(invoker.cpp_only)) {
cpp_only = invoker.cpp_only
@@ -317,8 +716,6 @@ template("mojom") {
enabled_sources = []
if (defined(invoker.sources)) {
generator_cpp_outputs = []
- generator_js_outputs = []
- generator_java_outputs = []
variant_dash_suffix = ""
if (defined(variant)) {
variant_dash_suffix = "-${variant}"
@@ -350,72 +747,88 @@ template("mojom") {
}
_typemap_config = typemap.config
if (get_path_info(source, "abspath") == _typemap_config.mojom) {
- active_typemaps += [ typemap ]
- }
- }
- if (is_mac && defined(bindings_configuration.typemaps_mac)) {
- foreach(typemap, bindings_configuration.typemaps_mac) {
- _typemap_config = {
+ enabled = false
+ if (!defined(_typemap_config.os_whitelist)) {
+ enabled = true
+ } else {
+ foreach(os, _typemap_config.os_whitelist) {
+ if (os == "android" && is_android) {
+ enabled = true
+ } else if (os == "chromeos" && is_chromeos) {
+ enabled = true
+ } else if (os == "fuchsia" && is_fuchsia) {
+ enabled = true
+ } else if (os == "ios" && is_ios) {
+ enabled = true
+ } else if (os == "linux" && is_linux) {
+ enabled = true
+ } else if (os == "mac" && is_mac) {
+ enabled = true
+ } else if (os == "posix" && is_posix) {
+ enabled = true
+ } else if (os == "win" && is_win) {
+ enabled = true
+ }
+ }
}
- _typemap_config = typemap.config
- if (get_path_info(source, "abspath") == _typemap_config.mojom) {
+ if (enabled) {
active_typemaps += [ typemap ]
}
}
}
}
- if (!cpp_only) {
- generator_js_outputs =
- [ "{{source_gen_dir}}/{{source_name_part}}.mojom.js" ]
- generator_java_outputs =
- [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar" ]
- }
generator_target_name = "${target_name}${variant_suffix}__generator"
- action_foreach(generator_target_name) {
+ action(generator_target_name) {
script = mojom_generator_script
- inputs = mojom_generator_sources
+ inputs = mojom_generator_sources + jinja2_sources
sources = invoker.sources
deps = [
- ":$type_mappings_target_name",
- "//mojo/public/tools/bindings:precompile_templates",
- ]
- outputs = generator_cpp_outputs + generator_java_outputs +
- generator_js_outputs
+ ":$parsed_target_name",
+ ":$type_mappings_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ] + verify_deps_target_names
+ outputs = []
args = common_generator_args
-
- if (cpp_only) {
- args += [
- "-g",
- "c++",
- ]
- } else {
- args += [
- "-g",
- "c++,javascript,java",
+ filelist = []
+ foreach(source, invoker.sources) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ outputs += [
+ "$target_gen_dir/${source}${variant_dash_suffix}.cc",
+ "$target_gen_dir/${source}${variant_dash_suffix}.h",
]
}
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "-g",
+ "c++",
+ ]
+
if (defined(bindings_configuration.variant)) {
args += [
"--variant",
bindings_configuration.variant,
]
}
- depfile =
- "{{source_gen_dir}}/${generator_target_name}_{{source_name_part}}.d"
- args += [
- "--depfile",
- depfile,
- "--depfile_target",
- "{{source_gen_dir}}/{{source_name_part}}.mojom${variant_dash_suffix}.cc",
- ]
args += [
"--typemap",
rebase_path(type_mappings_path, root_build_dir),
]
+ if (defined(invoker.component_macro_prefix)) {
+ args += [
+ "--export_attribute",
+ "COMPONENT_EXPORT(${invoker.component_macro_prefix}" +
+ "${bindings_configuration.component_macro_suffix})",
+ "--export_header",
+ "base/component_export.h",
+ ]
+ }
+
if (defined(bindings_configuration.for_blink) &&
bindings_configuration.for_blink) {
args += [ "--for_blink" ]
@@ -438,19 +851,20 @@ template("mojom") {
}
}
- if (defined(invoker.use_once_callback) && invoker.use_once_callback) {
+ if (!defined(invoker.use_once_callback) || invoker.use_once_callback) {
args += [ "--use_once_callback" ]
}
- if (defined(invoker.use_new_js_bindings) &&
- invoker.use_new_js_bindings) {
- args += [ "--use_new_js_bindings" ]
+ if (defined(invoker.support_lazy_serialization) &&
+ invoker.support_lazy_serialization) {
+ args += [ "--support_lazy_serialization" ]
}
}
}
action(type_mappings_target_name) {
- inputs = _bindings_configuration_files
+ inputs = _bindings_configuration_files + mojom_generator_sources +
+ jinja2_sources
outputs = [
type_mappings_path,
]
@@ -511,7 +925,16 @@ template("mojom") {
}
}
- source_set("${target_name}${variant_suffix}") {
+ if (defined(invoker.component_macro_prefix)) {
+ output_target_type = "component"
+ } else {
+ output_target_type = "source_set"
+ }
+
+ js_data_deps_target_name = target_name + "_js_data_deps"
+ not_needed([ "js_data_deps_target_name" ])
+
+ target("jumbo_" + output_target_type, "${target_name}${variant_suffix}") {
if (defined(bindings_configuration.for_blink) &&
bindings_configuration.for_blink &&
defined(invoker.visibility_blink)) {
@@ -522,13 +945,7 @@ template("mojom") {
if (defined(invoker.testonly)) {
testonly = invoker.testonly
}
- if (defined(invoker.sources) && !defined(bindings_configuration.variant)) {
- data = process_file_template(enabled_sources, generator_js_outputs)
- }
defines = []
- if (defined(invoker.testonly)) {
- testonly = invoker.testonly
- }
if (defined(invoker.export_define)) {
defines += [ invoker.export_define ]
}
@@ -539,18 +956,29 @@ template("mojom") {
sources = process_file_template(enabled_sources, generator_cpp_outputs)
}
deps = [
+ ":$generator_cpp_message_ids_target_name",
"//mojo/public/cpp/bindings:struct_traits",
"//mojo/public/interfaces/bindings:bindings__generator",
"//mojo/public/interfaces/bindings:bindings_shared__generator",
]
public_deps = [
- ":$shared_cpp_sources_target_name",
+ ":$shared_cpp_library_target_name",
"//base",
- "//mojo/public/cpp/bindings",
]
+ if (require_full_cpp_deps) {
+ public_deps += [ "//mojo/public/cpp/bindings" ]
+ } else {
+ public_deps += [ "//mojo/public/cpp/bindings:bindings_base" ]
+ }
+
if (enabled_sources != []) {
public_deps += [ ":$generator_target_name" ]
}
+ if (defined(invoker.component_macro_prefix)) {
+ output_name = "${invoker.component_output_prefix}${variant_suffix}"
+ defines += [ "IS_${invoker.component_macro_prefix}" +
+ "${bindings_configuration.component_macro_suffix}_IMPL" ]
+ }
foreach(d, all_deps) {
# Resolve the name, so that a target //mojo/something becomes
# //mojo/something:something and we can append variant_suffix to
@@ -570,7 +998,13 @@ template("mojom") {
}
public_deps += invoker.component_deps_blink
}
+ if (defined(invoker.check_includes_blink)) {
+ check_includes = invoker.check_includes_blink
+ }
} else {
+ if (defined(invoker.check_includes_blink)) {
+ not_needed(invoker, [ "check_includes_blink" ])
+ }
if (defined(invoker.overridden_deps)) {
foreach(d, invoker.overridden_deps) {
# Resolve the name, so that a target //mojo/something becomes
@@ -586,12 +1020,6 @@ template("mojom") {
_typemap_config = {
}
_typemap_config = typemap.config
- if (defined(_typemap_config.public_headers)) {
- sources += _typemap_config.public_headers
- }
- if (defined(_typemap_config.traits_headers)) {
- sources += _typemap_config.traits_headers
- }
if (defined(_typemap_config.sources)) {
sources += _typemap_config.sources
}
@@ -602,15 +1030,63 @@ template("mojom") {
deps += _typemap_config.deps
}
}
+ if (defined(invoker.export_header)) {
+ sources += [ "//" + invoker.export_header ]
+ }
if (defined(bindings_configuration.for_blink) &&
bindings_configuration.for_blink) {
public_deps += [ "//mojo/public/cpp/bindings:wtf_support" ]
}
+
+ if (enable_ipc_fuzzer) {
+ # Generate JS bindings by default if IPC fuzzer is enabled.
+ public_deps += [ ":$js_data_deps_target_name" ]
+ }
}
if (!cpp_only && is_android) {
import("//build/config/android/rules.gni")
+ java_generator_target_name = target_name + "_java__generator"
+ if (enabled_sources != []) {
+ generator_java_outputs =
+ [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar" ]
+ action(java_generator_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = enabled_sources
+ deps = [
+ ":$parsed_target_name",
+ ":$type_mappings_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ] + verify_deps_target_names
+ outputs = []
+ args = common_generator_args
+ filelist = []
+ foreach(source, invoker.sources) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ outputs += [ "$target_gen_dir/$source.srcjar" ]
+ }
+
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "-g",
+ "java",
+ ]
+
+ if (!defined(invoker.scramble_message_ids) ||
+ invoker.scramble_message_ids) {
+ inputs += message_scrambling_inputs
+ args += message_scrambling_args
+ }
+ }
+ } else {
+ group(java_generator_target_name) {
+ }
+ }
+
java_srcjar_target_name = target_name + "_java_sources"
action(java_srcjar_target_name) {
script = "//mojo/public/tools/gn/zip.py"
@@ -632,7 +1108,7 @@ template("mojom") {
deps = []
if (enabled_sources != []) {
deps = [
- ":$generator_target_name",
+ ":$java_generator_target_name",
]
}
}
@@ -645,6 +1121,9 @@ template("mojom") {
"//mojo/public/java:system_java",
]
+ # Disable warnings/checks on these generated files.
+ chromium_code = false
+
foreach(d, all_deps) {
# Resolve the name, so that a target //mojo/something becomes
# //mojo/something:something and we can append "_java" to get the java
@@ -654,8 +1133,104 @@ template("mojom") {
}
srcjar_deps = [ ":$java_srcjar_target_name" ]
- run_findbugs_override = false
}
}
}
+
+ if (enable_ipc_fuzzer || !defined(invoker.cpp_only) || !invoker.cpp_only) {
+ if (defined(invoker.sources)) {
+ generator_js_target_name = "${target_name}_js__generator"
+ generator_js_outputs = [
+ "{{source_gen_dir}}/{{source_name_part}}.mojom.js",
+ "{{source_gen_dir}}/{{source_name_part}}.mojom.externs.js",
+ ]
+ action(generator_js_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = []
+ if (defined(invoker.sources)) {
+ sources += invoker.sources
+ }
+ deps = [
+ ":$parsed_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ] + verify_deps_target_names
+ outputs = []
+ args = common_generator_args
+ filelist = []
+ foreach(source, invoker.sources) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ outputs += [
+ "$target_gen_dir/$source.js",
+ "$target_gen_dir/$source.externs.js",
+ ]
+ }
+
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "-g",
+ "javascript",
+ ]
+
+ if (!defined(invoker.scramble_message_ids) ||
+ invoker.scramble_message_ids) {
+ inputs += message_scrambling_inputs
+ args += message_scrambling_args
+ }
+
+ if (enable_ipc_fuzzer) {
+ args += [ "--generate_fuzzing" ]
+ }
+ }
+ }
+
+ js_target_name = target_name + "_js"
+ group(js_target_name) {
+ public_deps = []
+ if (defined(invoker.sources)) {
+ public_deps += [ ":$generator_js_target_name" ]
+ }
+
+ foreach(d, all_deps) {
+ full_name = get_label_info(d, "label_no_toolchain")
+ public_deps += [ "${full_name}_js" ]
+ }
+ }
+
+ group(js_data_deps_target_name) {
+ deps = []
+ if (defined(invoker.sources)) {
+ data = process_file_template(invoker.sources, generator_js_outputs)
+ deps += [ ":$generator_js_target_name" ]
+ }
+
+ data_deps = []
+ foreach(d, all_deps) {
+ full_name = get_label_info(d, "label_no_toolchain")
+ data_deps += [ "${full_name}_js_data_deps" ]
+ }
+ }
+ }
+}
+
+# A helper for the mojom() template above when component libraries are desired
+# for generated C++ bindings units. Supports all the same arguments as mojom()
+# except for the optional |component_output_prefix| and |component_macro_prefix|
+# arguments. These are instead shortened to |output_prefix| and |macro_prefix|
+# and are *required*.
+template("mojom_component") {
+ assert(defined(invoker.output_prefix) && defined(invoker.macro_prefix))
+
+ mojom(target_name) {
+ forward_variables_from(invoker,
+ "*",
+ [
+ "output_prefix",
+ "macro_prefix",
+ ])
+ component_output_prefix = invoker.output_prefix
+ component_macro_prefix = invoker.macro_prefix
+ }
}
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py
index a9650d7764..57a803178e 100755
--- a/mojo/public/tools/bindings/mojom_bindings_generator.py
+++ b/mojo/public/tools/bindings/mojom_bindings_generator.py
@@ -7,11 +7,14 @@
import argparse
-import imp
+import cPickle
+import hashlib
+import importlib
import json
import os
import pprint
import re
+import struct
import sys
# Disable lint check for finding modules:
@@ -37,15 +40,17 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
from mojom.error import Error
import mojom.fileutil as fileutil
-from mojom.generate import translate
from mojom.generate import template_expander
+from mojom.generate import translate
+from mojom.generate.generator import AddComputedData, WriteFile
+from mojom.parse.conditional_features import RemoveDisabledDefinitions
from mojom.parse.parser import Parse
_BUILTIN_GENERATORS = {
- "c++": "mojom_cpp_generator.py",
- "javascript": "mojom_js_generator.py",
- "java": "mojom_java_generator.py",
+ "c++": "mojom_cpp_generator",
+ "javascript": "mojom_js_generator",
+ "java": "mojom_java_generator",
}
@@ -53,18 +58,14 @@ def LoadGenerators(generators_string):
if not generators_string:
return [] # No generators.
- script_dir = os.path.dirname(os.path.abspath(__file__))
generators = {}
for generator_name in [s.strip() for s in generators_string.split(",")]:
language = generator_name.lower()
- if language in _BUILTIN_GENERATORS:
- generator_name = os.path.join(script_dir, "generators",
- _BUILTIN_GENERATORS[language])
- else:
+ if language not in _BUILTIN_GENERATORS:
print "Unknown generator name %s" % generator_name
sys.exit(1)
- generator_module = imp.load_source(os.path.basename(generator_name)[:-3],
- generator_name)
+ generator_module = importlib.import_module(
+ "generators.%s" % _BUILTIN_GENERATORS[language])
generators[language] = generator_module
return generators
@@ -100,6 +101,43 @@ def FindImportFile(rel_dir, file_name, search_rel_dirs):
rel_dir.source_root)
+def ScrambleMethodOrdinals(interfaces, salt):
+ already_generated = set()
+ for interface in interfaces:
+ i = 0
+ already_generated.clear()
+ for method in interface.methods:
+ while True:
+ i = i + 1
+ if i == 1000000:
+ raise Exception("Could not generate %d method ordinals for %s" %
+ (len(interface.methods), interface.mojom_name))
+ # Generate a scrambled method.ordinal value. The algorithm doesn't have
+ # to be very strong, cryptographically. It just needs to be non-trivial
+ # to guess the results without the secret salt, in order to make it
+ # harder for a compromised process to send fake Mojo messages.
+ sha256 = hashlib.sha256(salt)
+ sha256.update(interface.mojom_name)
+ sha256.update(str(i))
+ # Take the first 4 bytes as a little-endian uint32.
+ ordinal = struct.unpack('<L', sha256.digest()[:4])[0]
+ # Trim to 31 bits, so it always fits into a Java (signed) int.
+ ordinal = ordinal & 0x7fffffff
+ if ordinal in already_generated:
+ continue
+ already_generated.add(ordinal)
+ method.ordinal = ordinal
+ method.ordinal_comment = (
+ 'The %s value is based on sha256(salt + "%s%d").' %
+ (ordinal, interface.mojom_name, i))
+ break
+
+
+def ReadFileContents(filename):
+ with open(filename, 'rb') as f:
+ return f.read()
+
+
class MojomProcessor(object):
"""Parses mojom files and creates ASTs for them.
@@ -110,7 +148,6 @@ class MojomProcessor(object):
def __init__(self, should_generate):
self._should_generate = should_generate
self._processed_files = {}
- self._parsed_files = {}
self._typemap = {}
def LoadTypemaps(self, typemaps):
@@ -126,21 +163,20 @@ class MojomProcessor(object):
language_map.update(typemap)
self._typemap[language] = language_map
- def ProcessFile(self, args, remaining_args, generator_modules, filename):
- self._ParseFileAndImports(RelativePath(filename, args.depth),
- args.import_directories, [])
-
- return self._GenerateModule(args, remaining_args, generator_modules,
- RelativePath(filename, args.depth))
-
def _GenerateModule(self, args, remaining_args, generator_modules,
- rel_filename):
+ rel_filename, imported_filename_stack):
# Return the already-generated module.
if rel_filename.path in self._processed_files:
return self._processed_files[rel_filename.path]
- tree = self._parsed_files[rel_filename.path]
- dirname, name = os.path.split(rel_filename.path)
+ if rel_filename.path in imported_filename_stack:
+ print "%s: Error: Circular dependency" % rel_filename.path + \
+ MakeImportStackMessage(imported_filename_stack + [rel_filename.path])
+ sys.exit(1)
+
+ tree = _UnpickleAST(_FindPicklePath(rel_filename, args.gen_directories +
+ [args.output_dir]))
+ dirname = os.path.dirname(rel_filename.path)
# Process all our imports first and collect the module object for each.
# We use these to generate proper type info.
@@ -150,27 +186,37 @@ class MojomProcessor(object):
RelativePath(dirname, rel_filename.source_root),
parsed_imp.import_filename, args.import_directories)
imports[parsed_imp.import_filename] = self._GenerateModule(
- args, remaining_args, generator_modules, rel_import_file)
+ args, remaining_args, generator_modules, rel_import_file,
+ imported_filename_stack + [rel_filename.path])
- module = translate.OrderedModule(tree, name, imports)
+ # Set the module path as relative to the source root.
+ # Normalize to unix-style path here to keep the generators simpler.
+ module_path = rel_filename.relative_path().replace('\\', '/')
- # Set the path as relative to the source root.
- module.path = rel_filename.relative_path()
+ module = translate.OrderedModule(tree, module_path, imports)
- # Normalize to unix-style path here to keep the generators simpler.
- module.path = module.path.replace('\\', '/')
+ if args.scrambled_message_id_salt_paths:
+ salt = ''.join(
+ map(ReadFileContents, args.scrambled_message_id_salt_paths))
+ ScrambleMethodOrdinals(module.interfaces, salt)
if self._should_generate(rel_filename.path):
+ AddComputedData(module)
for language, generator_module in generator_modules.iteritems():
generator = generator_module.Generator(
module, args.output_dir, typemap=self._typemap.get(language, {}),
variant=args.variant, bytecode_path=args.bytecode_path,
for_blink=args.for_blink,
use_once_callback=args.use_once_callback,
- use_new_js_bindings=args.use_new_js_bindings,
+ js_bindings_mode=args.js_bindings_mode,
export_attribute=args.export_attribute,
export_header=args.export_header,
- generate_non_variant_code=args.generate_non_variant_code)
+ generate_non_variant_code=args.generate_non_variant_code,
+ support_lazy_serialization=args.support_lazy_serialization,
+ disallow_native_types=args.disallow_native_types,
+ disallow_interfaces=args.disallow_interfaces,
+ generate_message_ids=args.generate_message_ids,
+ generate_fuzzing=args.generate_fuzzing)
filtered_args = []
if hasattr(generator_module, 'GENERATOR_PREFIX'):
prefix = '--' + generator_module.GENERATOR_PREFIX + '_'
@@ -182,42 +228,6 @@ class MojomProcessor(object):
self._processed_files[rel_filename.path] = module
return module
- def _ParseFileAndImports(self, rel_filename, import_directories,
- imported_filename_stack):
- # Ignore already-parsed files.
- if rel_filename.path in self._parsed_files:
- return
-
- if rel_filename.path in imported_filename_stack:
- print "%s: Error: Circular dependency" % rel_filename.path + \
- MakeImportStackMessage(imported_filename_stack + [rel_filename.path])
- sys.exit(1)
-
- try:
- with open(rel_filename.path) as f:
- source = f.read()
- except IOError as e:
- print "%s: Error: %s" % (rel_filename.path, e.strerror) + \
- MakeImportStackMessage(imported_filename_stack + [rel_filename.path])
- sys.exit(1)
-
- try:
- tree = Parse(source, rel_filename.path)
- except Error as e:
- full_stack = imported_filename_stack + [rel_filename.path]
- print str(e) + MakeImportStackMessage(full_stack)
- sys.exit(1)
-
- dirname = os.path.split(rel_filename.path)[0]
- for imp_entry in tree.import_list:
- import_file_entry = FindImportFile(
- RelativePath(dirname, rel_filename.source_root),
- imp_entry.import_filename, import_directories)
- self._ParseFileAndImports(import_file_entry, import_directories,
- imported_filename_stack + [rel_filename.path])
-
- self._parsed_files[rel_filename.path] = tree
-
def _Generate(args, remaining_args):
if args.variant == "none":
@@ -235,15 +245,78 @@ def _Generate(args, remaining_args):
processor = MojomProcessor(lambda filename: filename in args.filename)
processor.LoadTypemaps(set(args.typemaps))
+
+ if args.filelist:
+ with open(args.filelist) as f:
+ args.filename.extend(f.read().split())
+
for filename in args.filename:
- processor.ProcessFile(args, remaining_args, generator_modules, filename)
- if args.depfile:
- assert args.depfile_target
- with open(args.depfile, 'w') as f:
- f.write('%s: %s' % (
- args.depfile_target,
- ' '.join(processor._parsed_files.keys())))
+ processor._GenerateModule(args, remaining_args, generator_modules,
+ RelativePath(filename, args.depth), [])
+
+ return 0
+
+
+def _FindPicklePath(rel_filename, search_dirs):
+ filename, _ = os.path.splitext(rel_filename.relative_path())
+ pickle_path = filename + '.p'
+ for search_dir in search_dirs:
+ path = os.path.join(search_dir, pickle_path)
+ if os.path.isfile(path):
+ return path
+ raise Exception("%s: Error: Could not find file in %r" % (pickle_path, search_dirs))
+
+
+def _GetPicklePath(rel_filename, output_dir):
+ filename, _ = os.path.splitext(rel_filename.relative_path())
+ pickle_path = filename + '.p'
+ return os.path.join(output_dir, pickle_path)
+
+
+def _PickleAST(ast, output_file):
+ full_dir = os.path.dirname(output_file)
+ fileutil.EnsureDirectoryExists(full_dir)
+
+ try:
+ WriteFile(cPickle.dumps(ast), output_file)
+ except (IOError, cPickle.PicklingError) as e:
+ print "%s: Error: %s" % (output_file, str(e))
+ sys.exit(1)
+
+def _UnpickleAST(input_file):
+ try:
+ with open(input_file, "rb") as f:
+ return cPickle.load(f)
+ except (IOError, cPickle.UnpicklingError) as e:
+ print "%s: Error: %s" % (input_file, str(e))
+ sys.exit(1)
+
+def _ParseFile(args, rel_filename):
+ try:
+ with open(rel_filename.path) as f:
+ source = f.read()
+ except IOError as e:
+ print "%s: Error: %s" % (rel_filename.path, e.strerror)
+ sys.exit(1)
+
+ try:
+ tree = Parse(source, rel_filename.path)
+ RemoveDisabledDefinitions(tree, args.enabled_features)
+ except Error as e:
+ print "%s: Error: %s" % (rel_filename.path, str(e))
+ sys.exit(1)
+ _PickleAST(tree, _GetPicklePath(rel_filename, args.output_dir))
+
+
+def _Parse(args, _):
+ fileutil.EnsureDirectoryExists(args.output_dir)
+ if args.filelist:
+ with open(args.filelist) as f:
+ args.filename.extend(f.read().split())
+
+ for filename in args.filename:
+ _ParseFile(args, RelativePath(filename, args.depth))
return 0
@@ -253,7 +326,46 @@ def _Precompile(args, _):
template_expander.PrecompileTemplates(generator_modules, args.output_dir)
return 0
+def _VerifyImportDeps(args, __):
+ fileutil.EnsureDirectoryExists(args.gen_dir)
+
+ if args.filelist:
+ with open(args.filelist) as f:
+ args.filename.extend(f.read().split())
+ for filename in args.filename:
+ rel_path = RelativePath(filename, args.depth)
+ tree = _UnpickleAST(_GetPicklePath(rel_path, args.gen_dir))
+
+ mojom_imports = set(
+ parsed_imp.import_filename for parsed_imp in tree.import_list
+ )
+
+ # read the paths from the file
+ f_deps = open(args.deps_file, 'r')
+ deps_sources = set()
+ for deps_path in f_deps:
+ deps_path = deps_path.rstrip('\n')
+ f_sources = open(deps_path, 'r')
+
+ for source_file in f_sources:
+ source_dir = deps_path.split(args.gen_dir + "/", 1)[1]
+ full_source_path = os.path.dirname(source_dir) + "/" + \
+ source_file
+ deps_sources.add(full_source_path.rstrip('\n'))
+
+ if (not deps_sources.issuperset(mojom_imports)):
+ print ">>> [%s] Missing dependencies for the following imports: %s" % ( \
+ args.filename[0], \
+ list(mojom_imports.difference(deps_sources)))
+ sys.exit(1)
+
+ source_filename, _ = os.path.splitext(rel_path.relative_path())
+ output_file = source_filename + '.v'
+ output_file_path = os.path.join(args.gen_dir, output_file)
+ WriteFile("", output_file_path)
+
+ return 0
def main():
parser = argparse.ArgumentParser(
@@ -262,10 +374,35 @@ def main():
help="use Python modules bundled in the SDK")
subparsers = parser.add_subparsers()
+
+ parse_parser = subparsers.add_parser(
+ "parse", description="Parse mojom to AST and remove disabled definitions."
+ " Pickle pruned AST into output_dir.")
+ parse_parser.add_argument("filename", nargs="*", help="mojom input file")
+ parse_parser.add_argument("--filelist", help="mojom input file list")
+ parse_parser.add_argument(
+ "-o",
+ "--output_dir",
+ dest="output_dir",
+ default=".",
+ help="output directory for generated files")
+ parse_parser.add_argument(
+ "-d", "--depth", dest="depth", default=".", help="depth from source root")
+ parse_parser.add_argument(
+ "--enable_feature",
+ dest = "enabled_features",
+ default=[],
+ action="append",
+ help="Controls which definitions guarded by an EnabledIf attribute "
+ "will be enabled. If an EnabledIf attribute does not specify a value "
+ "that matches one of the enabled features, it will be disabled.")
+ parse_parser.set_defaults(func=_Parse)
+
generate_parser = subparsers.add_parser(
"generate", description="Generate bindings from mojom files.")
- generate_parser.add_argument("filename", nargs="+",
+ generate_parser.add_argument("filename", nargs="*",
help="mojom input file")
+ generate_parser.add_argument("--filelist", help="mojom input file list")
generate_parser.add_argument("-d", "--depth", dest="depth", default=".",
help="depth from source root")
generate_parser.add_argument("-o", "--output_dir", dest="output_dir",
@@ -277,6 +414,9 @@ def main():
default="c++,javascript,java",
help="comma-separated list of generators")
generate_parser.add_argument(
+ "--gen_dir", dest="gen_directories", action="append", metavar="directory",
+ default=[], help="add a directory to be searched for the syntax trees.")
+ generate_parser.add_argument(
"-I", dest="import_directories", action="append", metavar="directory",
default=[],
help="add a directory to be searched for import files. The depth from "
@@ -288,7 +428,7 @@ def main():
generate_parser.add_argument("--variant", dest="variant", default=None,
help="output a named variant of the bindings")
generate_parser.add_argument(
- "--bytecode_path", type=str, required=True, help=(
+ "--bytecode_path", required=True, help=(
"the path from which to load template bytecode; to generate template "
"bytecode, run %s precompile BYTECODE_PATH" % os.path.basename(
sys.argv[0])))
@@ -299,26 +439,52 @@ def main():
"--use_once_callback", action="store_true",
help="Use base::OnceCallback instead of base::RepeatingCallback.")
generate_parser.add_argument(
- "--use_new_js_bindings", action="store_true",
- help="Use the new module loading approach and the core API exposed by "
- "Web IDL. This option only affects the JavaScript bindings.")
+ "--js_bindings_mode", choices=["new", "both", "old"], default="new",
+ help="This option only affects the JavaScript bindings. The value could "
+ "be: \"new\" - generate only the new-style JS bindings, which use the "
+ "new module loading approach and the core api exposed by Web IDL; "
+ "\"both\" - generate both the old- and new-style bindings; \"old\" - "
+ "generate only the old-style bindings.")
generate_parser.add_argument(
- "--export_attribute", type=str, default="",
+ "--export_attribute", default="",
help="Optional attribute to specify on class declaration to export it "
"for the component build.")
generate_parser.add_argument(
- "--export_header", type=str, default="",
+ "--export_header", default="",
help="Optional header to include in the generated headers to support the "
"component build.")
generate_parser.add_argument(
"--generate_non_variant_code", action="store_true",
help="Generate code that is shared by different variants.")
generate_parser.add_argument(
- "--depfile", type=str,
- help="A file into which the list of input files will be written.")
+ "--scrambled_message_id_salt_path",
+ dest="scrambled_message_id_salt_paths",
+ help="If non-empty, the path to a file whose contents should be used as"
+ "a salt for generating scrambled message IDs. If this switch is specified"
+ "more than once, the contents of all salt files are concatenated to form"
+ "the salt value.", default=[], action="append")
+ generate_parser.add_argument(
+ "--support_lazy_serialization",
+ help="If set, generated bindings will serialize lazily when possible.",
+ action="store_true")
generate_parser.add_argument(
- "--depfile_target", type=str,
- help="The target name to use in the depfile.")
+ "--disallow_native_types",
+ help="Disallows the [Native] attribute to be specified on structs or "
+ "enums within the mojom file.", action="store_true")
+ generate_parser.add_argument(
+ "--disallow_interfaces",
+ help="Disallows interface definitions within the mojom file. It is an "
+ "error to specify this flag when processing a mojom file which defines "
+ "any interface.", action="store_true")
+ generate_parser.add_argument(
+ "--generate_message_ids",
+ help="Generates only the message IDs header for C++ bindings. Note that "
+ "this flag only matters if --generate_non_variant_code is also "
+ "specified.", action="store_true")
+ generate_parser.add_argument(
+ "--generate_fuzzing",
+ action="store_true",
+ help="Generates additional bindings for fuzzing in JS.")
generate_parser.set_defaults(func=_Generate)
precompile_parser = subparsers.add_parser("precompile",
@@ -328,6 +494,23 @@ def main():
help="output directory for precompiled templates")
precompile_parser.set_defaults(func=_Precompile)
+ verify_parser = subparsers.add_parser("verify", description="Checks "
+ "the set of imports against the set of dependencies.")
+ verify_parser.add_argument("filename", nargs="*",
+ help="mojom input file")
+ verify_parser.add_argument("--filelist", help="mojom input file list")
+ verify_parser.add_argument("-f", "--file", dest="deps_file",
+ help="file containing paths to the sources files for "
+ "dependencies")
+ verify_parser.add_argument("-g", "--gen_dir",
+ dest="gen_dir",
+ help="directory with the syntax tree")
+ verify_parser.add_argument(
+ "-d", "--depth", dest="depth",
+ help="depth from source root")
+
+ verify_parser.set_defaults(func=_VerifyImportDeps)
+
args, remaining_args = parser.parse_known_args()
return args.func(args, remaining_args)
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py b/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
index de388561cb..bcffbbb116 100644
--- a/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
+++ b/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
@@ -5,6 +5,19 @@
import unittest
from mojom_bindings_generator import MakeImportStackMessage
+from mojom_bindings_generator import ScrambleMethodOrdinals
+
+
+class FakeIface(object):
+ def __init__( self ):
+ self.name = None
+ self.methods = None
+
+
+class FakeMethod(object):
+ def __init__( self ):
+ self.ordinal = None
+ self.ordinal_comment = None
class MojoBindingsGeneratorTest(unittest.TestCase):
@@ -18,6 +31,23 @@ class MojoBindingsGeneratorTest(unittest.TestCase):
self.assertEquals(MakeImportStackMessage(["x", "y", "z"]),
"\n z was imported by y\n y was imported by x")
+ def testScrambleMethodOrdinals(self):
+ """Tests ScrambleMethodOrdinals()."""
+ interface = FakeIface()
+ interface.name = 'RendererConfiguration'
+ interface.methods = [FakeMethod(), FakeMethod(), FakeMethod()]
+ ScrambleMethodOrdinals([interface], "foo")
+ # These next three values are hard-coded. If the generation algorithm
+ # changes from being based on sha256(seed + interface.name + str(i)) then
+ # these numbers will obviously need to change too.
+ #
+ # Note that hashlib.sha256('fooRendererConfiguration1').digest()[:4] is
+ # '\xa5\xbc\xf9\xca' and that hex(1257880741) = '0x4af9bca5'. The
+ # difference in 0x4a vs 0xca is because we only take 31 bits.
+ self.assertEquals(interface.methods[0].ordinal, 1257880741)
+ self.assertEquals(interface.methods[1].ordinal, 631133653)
+ self.assertEquals(interface.methods[2].ordinal, 549336076)
+
if __name__ == "__main__":
unittest.main()
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
index 0e64af78a1..acf029f6a1 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
@@ -12,142 +12,191 @@ import module as mojom
import mojom.fileutil as fileutil
import pack
+
def ExpectedArraySize(kind):
if mojom.IsArrayKind(kind):
return kind.length
return None
-def StudlyCapsToCamel(studly):
- return studly[0].lower() + studly[1:]
-def UnderToCamel(under):
- """Converts underscore_separated strings to CamelCase strings."""
- return ''.join(word.capitalize() for word in under.split('_'))
+def ToCamel(identifier, lower_initial=False, dilimiter='_'):
+ """Splits |identifier| using |dilimiter|, makes the first character of each
+ word uppercased (but makes the first character of the first word lowercased
+ if |lower_initial| is set to True), and joins the words. Please note that for
+ each word, all the characters except the first one are untouched.
+ """
+ result = ''.join(word[0].upper() + word[1:]
+ for word in identifier.split(dilimiter) if word)
+ if lower_initial and result:
+ result = result[0].lower() + result[1:]
+ return result
-def WriteFile(contents, full_path):
- # Make sure the containing directory exists.
- full_dir = os.path.dirname(full_path)
- fileutil.EnsureDirectoryExists(full_dir)
- # Dump the data to disk.
- with open(full_path, "w+") as f:
- f.write(contents)
+class Stylizer(object):
+ """Stylizers specify naming rules to map mojom names to names in generated
+ code. For example, if you would like method_name in mojom to be mapped to
+ MethodName in the generated code, you need to define a subclass of Stylizer
+ and override StylizeMethod to do the conversion."""
-class Generator(object):
- # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all
- # files to stdout.
- def __init__(self, module, output_dir=None, typemap=None, variant=None,
- bytecode_path=None, for_blink=False, use_once_callback=False,
- use_new_js_bindings=False, export_attribute=None,
- export_header=None, generate_non_variant_code=False):
- self.module = module
- self.output_dir = output_dir
- self.typemap = typemap or {}
- self.variant = variant
- self.bytecode_path = bytecode_path
- self.for_blink = for_blink
- self.use_once_callback = use_once_callback
- self.use_new_js_bindings = use_new_js_bindings
- self.export_attribute = export_attribute
- self.export_header = export_header
- self.generate_non_variant_code = generate_non_variant_code
+ def StylizeConstant(self, mojom_name):
+ return mojom_name
- def GetStructsFromMethods(self):
- result = []
- for interface in self.module.interfaces:
- for method in interface.methods:
- result.append(self._GetStructFromMethod(method))
- if method.response_parameters != None:
- result.append(self._GetResponseStructFromMethod(method))
- return result
+ def StylizeField(self, mojom_name):
+ return mojom_name
- def GetStructs(self):
- return map(partial(self._AddStructComputedData, True), self.module.structs)
+ def StylizeStruct(self, mojom_name):
+ return mojom_name
- def GetUnions(self):
- return map(self._AddUnionComputedData, self.module.unions)
+ def StylizeUnion(self, mojom_name):
+ return mojom_name
- def GetInterfaces(self):
- return map(self._AddInterfaceComputedData, self.module.interfaces)
+ def StylizeParameter(self, mojom_name):
+ return mojom_name
- # Prepend the filename with a directory that matches the directory of the
- # original .mojom file, relative to the import root.
- def MatchMojomFilePath(self, filename):
- return os.path.join(os.path.dirname(self.module.path), filename)
+ def StylizeMethod(self, mojom_name):
+ return mojom_name
- def Write(self, contents, filename):
- if self.output_dir is None:
- print contents
- return
- full_path = os.path.join(self.output_dir, filename)
- WriteFile(contents, full_path)
+ def StylizeInterface(self, mojom_name):
+ return mojom_name
- def GenerateFiles(self, args):
- raise NotImplementedError("Subclasses must override/implement this method")
+ def StylizeEnumField(self, mojom_name):
+ return mojom_name
- def GetJinjaParameters(self):
- """Returns default constructor parameters for the jinja environment."""
- return {}
+ def StylizeEnum(self, mojom_name):
+ return mojom_name
+
+ def StylizeModule(self, mojom_namespace):
+ return mojom_namespace
+
+
+def WriteFile(contents, full_path):
+ # If |contents| is same with the file content, we skip updating.
+ if os.path.isfile(full_path):
+ with open(full_path, 'rb') as destination_file:
+ if destination_file.read() == contents:
+ return
+
+ # Make sure the containing directory exists.
+ full_dir = os.path.dirname(full_path)
+ fileutil.EnsureDirectoryExists(full_dir)
+
+ # Dump the data to disk.
+ with open(full_path, "wb") as f:
+ f.write(contents)
- def GetGlobals(self):
- """Returns global mappings for the template generation."""
- return {}
- def _AddStructComputedData(self, exported, struct):
- """Adds computed data to the given struct. The data is computed once and
- used repeatedly in the generation process."""
+def AddComputedData(module):
+ """Adds computed data to the given module. The data is computed once and
+ used repeatedly in the generation process."""
+
+ def _AddStructComputedData(exported, struct):
struct.packed = pack.PackedStruct(struct)
struct.bytes = pack.GetByteLayout(struct.packed)
struct.versions = pack.GetVersionInfo(struct.packed)
struct.exported = exported
- return struct
- def _AddUnionComputedData(self, union):
- """Adds computed data to the given union. The data is computed once and
- used repeatedly in the generation process."""
+ def _AddUnionComputedData(union):
ordinal = 0
for field in union.fields:
if field.ordinal is not None:
ordinal = field.ordinal
field.ordinal = ordinal
ordinal += 1
- return union
- def _AddInterfaceComputedData(self, interface):
- """Adds computed data to the given interface. The data is computed once and
- used repeatedly in the generation process."""
+ def _AddInterfaceComputedData(interface):
+ next_ordinal = 0
interface.version = 0
for method in interface.methods:
+ if method.ordinal is None:
+ method.ordinal = next_ordinal
+ next_ordinal = method.ordinal + 1
+
if method.min_version is not None:
interface.version = max(interface.version, method.min_version)
- method.param_struct = self._GetStructFromMethod(method)
+ method.param_struct = _GetStructFromMethod(method)
interface.version = max(interface.version,
method.param_struct.versions[-1].version)
if method.response_parameters is not None:
- method.response_param_struct = self._GetResponseStructFromMethod(method)
+ method.response_param_struct = _GetResponseStructFromMethod(method)
interface.version = max(
interface.version,
method.response_param_struct.versions[-1].version)
else:
method.response_param_struct = None
- return interface
- def _GetStructFromMethod(self, method):
+ def _GetStructFromMethod(method):
"""Converts a method's parameters into the fields of a struct."""
- params_class = "%s_%s_Params" % (method.interface.name, method.name)
+ params_class = "%s_%s_Params" % (method.interface.mojom_name,
+ method.mojom_name)
struct = mojom.Struct(params_class, module=method.interface.module)
for param in method.parameters:
- struct.AddField(param.name, param.kind, param.ordinal,
+ struct.AddField(param.mojom_name, param.kind, param.ordinal,
attributes=param.attributes)
- return self._AddStructComputedData(False, struct)
+ _AddStructComputedData(False, struct)
+ return struct
- def _GetResponseStructFromMethod(self, method):
+ def _GetResponseStructFromMethod(method):
"""Converts a method's response_parameters into the fields of a struct."""
- params_class = "%s_%s_ResponseParams" % (method.interface.name, method.name)
+ params_class = "%s_%s_ResponseParams" % (method.interface.mojom_name,
+ method.mojom_name)
struct = mojom.Struct(params_class, module=method.interface.module)
for param in method.response_parameters:
- struct.AddField(param.name, param.kind, param.ordinal,
+ struct.AddField(param.mojom_name, param.kind, param.ordinal,
attributes=param.attributes)
- return self._AddStructComputedData(False, struct)
+ _AddStructComputedData(False, struct)
+ return struct
+
+ for struct in module.structs:
+ _AddStructComputedData(True, struct)
+ for union in module.unions:
+ _AddUnionComputedData(union)
+ for interface in module.interfaces:
+ _AddInterfaceComputedData(interface)
+
+
+class Generator(object):
+ # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all
+ # files to stdout.
+ def __init__(self, module, output_dir=None, typemap=None, variant=None,
+ bytecode_path=None, for_blink=False, use_once_callback=False,
+ js_bindings_mode="new", export_attribute=None,
+ export_header=None, generate_non_variant_code=False,
+ support_lazy_serialization=False, disallow_native_types=False,
+ disallow_interfaces=False, generate_message_ids=False,
+ generate_fuzzing=False):
+ self.module = module
+ self.output_dir = output_dir
+ self.typemap = typemap or {}
+ self.variant = variant
+ self.bytecode_path = bytecode_path
+ self.for_blink = for_blink
+ self.use_once_callback = use_once_callback
+ self.js_bindings_mode = js_bindings_mode
+ self.export_attribute = export_attribute
+ self.export_header = export_header
+ self.generate_non_variant_code = generate_non_variant_code
+ self.support_lazy_serialization = support_lazy_serialization
+ self.disallow_native_types = disallow_native_types
+ self.disallow_interfaces = disallow_interfaces
+ self.generate_message_ids = generate_message_ids
+ self.generate_fuzzing = generate_fuzzing
+
+ def Write(self, contents, filename):
+ if self.output_dir is None:
+ print contents
+ return
+ full_path = os.path.join(self.output_dir, filename)
+ WriteFile(contents, full_path)
+
+ def GenerateFiles(self, args):
+ raise NotImplementedError("Subclasses must override/implement this method")
+
+ def GetJinjaParameters(self):
+ """Returns default constructor parameters for the jinja environment."""
+ return {}
+
+ def GetGlobals(self):
+ """Returns global mappings for the template generation."""
+ return {}
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/generator_unittest.py b/mojo/public/tools/bindings/pylib/mojom/generate/generator_unittest.py
deleted file mode 100644
index 9966b0b7f8..0000000000
--- a/mojo/public/tools/bindings/pylib/mojom/generate/generator_unittest.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2015 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.
-
-import unittest
-
-import module as mojom
-import generator
-
-class TestGenerator(unittest.TestCase):
-
- def testGetUnionsAddsOrdinals(self):
- module = mojom.Module()
- union = module.AddUnion('a')
- union.AddField('a', mojom.BOOL)
- union.AddField('b', mojom.BOOL)
- union.AddField('c', mojom.BOOL, ordinal=10)
- union.AddField('d', mojom.BOOL)
-
- gen = generator.Generator(module)
- union = gen.GetUnions()[0]
- ordinals = [field.ordinal for field in union.fields]
-
- self.assertEquals([0, 1, 10, 11], ordinals)
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
index 3a5f188e75..db45e3344f 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/module.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
@@ -12,7 +12,6 @@
# method = interface.AddMethod('Tat', 0)
# method.AddParameter('baz', 0, mojom.INT32)
-
# We use our own version of __repr__ when displaying the AST, as the
# AST currently doesn't capture which nodes are reference (e.g. to
# types) and which nodes are definitions. This allows us to e.g. print
@@ -82,11 +81,13 @@ class Kind(object):
Attributes:
spec: A string uniquely identifying the type. May be None.
- parent_kind: The enclosing type. For example, a struct defined
+ module: {Module} The defining module. Set to None for built-in types.
+ parent_kind: The enclosing type. For example, an enum defined
inside an interface has that interface as its parent. May be None.
"""
- def __init__(self, spec=None):
+ def __init__(self, spec=None, module=None):
self.spec = spec
+ self.module = module
self.parent_kind = None
def Repr(self, as_ref=True):
@@ -106,10 +107,9 @@ class ReferenceKind(Kind):
Attributes:
is_nullable: True if the type is nullable.
"""
-
- def __init__(self, spec=None, is_nullable=False):
+ def __init__(self, spec=None, is_nullable=False, module=None):
assert spec is None or is_nullable == spec.startswith('?')
- Kind.__init__(self, spec)
+ Kind.__init__(self, spec, module)
self.is_nullable = is_nullable
self.shared_definition = {}
@@ -138,6 +138,8 @@ class ReferenceKind(Kind):
if self.spec is not None:
nullable_kind.spec = '?' + self.spec
nullable_kind.is_nullable = True
+ nullable_kind.parent_kind = self.parent_kind
+ nullable_kind.module = self.module
return nullable_kind
@@ -222,17 +224,15 @@ ATTRIBUTE_SYNC = 'Sync'
class NamedValue(object):
- def __init__(self, module, parent_kind, name):
+ def __init__(self, module, parent_kind, mojom_name):
self.module = module
- self.namespace = module.namespace
self.parent_kind = parent_kind
- self.name = name
- self.imported_from = None
+ self.mojom_name = mojom_name
def GetSpec(self):
- return (self.namespace + '.' +
- (self.parent_kind and (self.parent_kind.name + '.') or "") +
- self.name)
+ return (self.module.mojom_namespace + '.' +
+ (self.parent_kind and (self.parent_kind.mojom_name + '.') or "") +
+ self.mojom_name)
class BuiltinValue(object):
@@ -242,35 +242,47 @@ class BuiltinValue(object):
class ConstantValue(NamedValue):
def __init__(self, module, parent_kind, constant):
- NamedValue.__init__(self, module, parent_kind, constant.name)
+ NamedValue.__init__(self, module, parent_kind, constant.mojom_name)
self.constant = constant
+ @property
+ def name(self):
+ return self.constant.name
+
class EnumValue(NamedValue):
def __init__(self, module, enum, field):
- NamedValue.__init__(self, module, enum.parent_kind, field.name)
+ NamedValue.__init__(self, module, enum.parent_kind, field.mojom_name)
+ self.field = field
self.enum = enum
def GetSpec(self):
- return (self.namespace + '.' +
- (self.parent_kind and (self.parent_kind.name + '.') or "") +
- self.enum.name + '.' + self.name)
+ return (self.module.mojom_namespace + '.' +
+ (self.parent_kind and (self.parent_kind.mojom_name + '.') or "") +
+ self.enum.mojom_name + '.' + self.mojom_name)
+
+ @property
+ def name(self):
+ return self.field.name
class Constant(object):
- def __init__(self, name=None, kind=None, value=None, parent_kind=None):
- self.name = name
+ def __init__(self, mojom_name=None, kind=None, value=None, parent_kind=None):
+ self.mojom_name = mojom_name
self.kind = kind
self.value = value
self.parent_kind = parent_kind
+ def Stylize(self, stylizer):
+ self.name = stylizer.StylizeConstant(self.mojom_name)
+
class Field(object):
- def __init__(self, name=None, kind=None, ordinal=None, default=None,
+ def __init__(self, mojom_name=None, kind=None, ordinal=None, default=None,
attributes=None):
if self.__class__.__name__ == 'Field':
raise Exception()
- self.name = name
+ self.mojom_name = mojom_name
self.kind = kind
self.ordinal = ordinal
self.default = default
@@ -279,7 +291,10 @@ class Field(object):
def Repr(self, as_ref=True):
# Fields are only referenced by objects which define them and thus
# they are always displayed as non-references.
- return GenericRepr(self, {'name': False, 'kind': True})
+ return GenericRepr(self, {'mojom_name': False, 'kind': True})
+
+ def Stylize(self, stylizer):
+ self.name = stylizer.StylizeField(self.mojom_name)
@property
def min_version(self):
@@ -297,80 +312,90 @@ class Struct(ReferenceKind):
"""A struct with typed fields.
Attributes:
- name: {str} The name of the struct type.
+ mojom_name: {str} The name of the struct type as defined in mojom.
+ name: {str} The stylized name.
native_only: {bool} Does the struct have a body (i.e. any fields) or is it
purely a native struct.
- module: {Module} The defining module.
- imported_from: {dict} Information about where this union was
- imported from.
+ custom_serializer: {bool} Should we generate a serializer for the struct or
+ will one be provided by non-generated code.
fields: {List[StructField]} The members of the struct.
+ enums: {List[Enum]} The enums defined in the struct scope.
+ constants: {List[Constant]} The constants defined in the struct scope.
attributes: {dict} Additional information about the struct, such as
if it's a native struct.
"""
+ ReferenceKind.AddSharedProperty('mojom_name')
ReferenceKind.AddSharedProperty('name')
ReferenceKind.AddSharedProperty('native_only')
- ReferenceKind.AddSharedProperty('module')
- ReferenceKind.AddSharedProperty('imported_from')
+ ReferenceKind.AddSharedProperty('custom_serializer')
ReferenceKind.AddSharedProperty('fields')
+ ReferenceKind.AddSharedProperty('enums')
+ ReferenceKind.AddSharedProperty('constants')
ReferenceKind.AddSharedProperty('attributes')
- def __init__(self, name=None, module=None, attributes=None):
- if name is not None:
- spec = 'x:' + name
+ def __init__(self, mojom_name=None, module=None, attributes=None):
+ if mojom_name is not None:
+ spec = 'x:' + mojom_name
else:
spec = None
- ReferenceKind.__init__(self, spec)
- self.name = name
+ ReferenceKind.__init__(self, spec, False, module)
+ self.mojom_name = mojom_name
self.native_only = False
- self.module = module
- self.imported_from = None
+ self.custom_serializer = False
self.fields = []
+ self.enums = []
+ self.constants = []
self.attributes = attributes
def Repr(self, as_ref=True):
if as_ref:
- return '<%s name=%r imported_from=%s>' % (
- self.__class__.__name__, self.name,
- Repr(self.imported_from, as_ref=True))
+ return '<%s mojom_name=%r module=%s>' % (
+ self.__class__.__name__, self.mojom_name,
+ Repr(self.module, as_ref=True))
else:
- return GenericRepr(self, {'name': False, 'fields': False,
- 'imported_from': True})
+ return GenericRepr(self,
+ {'mojom_name': False, 'fields': False, 'module': True})
- def AddField(self, name, kind, ordinal=None, default=None, attributes=None):
- field = StructField(name, kind, ordinal, default, attributes)
+ def AddField(self, mojom_name, kind, ordinal=None, default=None,
+ attributes=None):
+ field = StructField(mojom_name, kind, ordinal, default, attributes)
self.fields.append(field)
return field
+ def Stylize(self, stylizer):
+ self.name = stylizer.StylizeStruct(self.mojom_name)
+ for field in self.fields:
+ field.Stylize(stylizer)
+ for enum in self.enums:
+ enum.Stylize(stylizer)
+ for constant in self.constants:
+ constant.Stylize(stylizer)
+
class Union(ReferenceKind):
"""A union of several kinds.
Attributes:
- name: {str} The name of the union type.
- module: {Module} The defining module.
- imported_from: {dict} Information about where this union was
- imported from.
+ mojom_name: {str} The name of the union type as defined in mojom.
+ name: {str} The stylized name.
fields: {List[UnionField]} The members of the union.
attributes: {dict} Additional information about the union, such as
which Java class name to use to represent it in the generated
bindings.
"""
+ ReferenceKind.AddSharedProperty('mojom_name')
ReferenceKind.AddSharedProperty('name')
- ReferenceKind.AddSharedProperty('module')
- ReferenceKind.AddSharedProperty('imported_from')
ReferenceKind.AddSharedProperty('fields')
ReferenceKind.AddSharedProperty('attributes')
- def __init__(self, name=None, module=None, attributes=None):
- if name is not None:
- spec = 'x:' + name
+ def __init__(self, mojom_name=None, module=None, attributes=None):
+ if mojom_name is not None:
+ spec = 'x:' + mojom_name
else:
spec = None
- ReferenceKind.__init__(self, spec)
- self.name = name
- self.module = module
- self.imported_from = None
+ ReferenceKind.__init__(self, spec, False, module)
+ self.mojom_name = mojom_name
self.fields = []
self.attributes = attributes
@@ -382,11 +407,16 @@ class Union(ReferenceKind):
else:
return GenericRepr(self, {'fields': True, 'is_nullable': False})
- def AddField(self, name, kind, ordinal=None, attributes=None):
- field = UnionField(name, kind, ordinal, None, attributes)
+ def AddField(self, mojom_name, kind, ordinal=None, attributes=None):
+ field = UnionField(mojom_name, kind, ordinal, None, attributes)
self.fields.append(field)
return field
+ def Stylize(self, stylizer):
+ self.name = stylizer.StylizeUnion(self.mojom_name)
+ for field in self.fields:
+ field.Stylize(stylizer)
+
class Array(ReferenceKind):
"""An array.
@@ -491,17 +521,20 @@ class AssociatedInterfaceRequest(ReferenceKind):
class Parameter(object):
- def __init__(self, name=None, kind=None, ordinal=None, default=None,
+ def __init__(self, mojom_name=None, kind=None, ordinal=None, default=None,
attributes=None):
- self.name = name
+ self.mojom_name = mojom_name
self.ordinal = ordinal
self.kind = kind
self.default = default
self.attributes = attributes
def Repr(self, as_ref=True):
- return '<%s name=%r kind=%s>' % (self.__class__.__name__, self.name,
- self.kind.Repr(as_ref=True))
+ return '<%s mojom_name=%r kind=%s>' % (
+ self.__class__.__name__, self.mojom_name, self.kind.Repr(as_ref=True))
+
+ def Stylize(self, stylizer):
+ self.name = stylizer.StylizeParameter(self.mojom_name)
@property
def min_version(self):
@@ -510,35 +543,50 @@ class Parameter(object):
class Method(object):
- def __init__(self, interface, name, ordinal=None, attributes=None):
+ def __init__(self, interface, mojom_name, ordinal=None, attributes=None):
self.interface = interface
- self.name = name
+ self.mojom_name = mojom_name
self.ordinal = ordinal
self.parameters = []
+ self.param_struct = None
self.response_parameters = None
+ self.response_param_struct = None
self.attributes = attributes
def Repr(self, as_ref=True):
if as_ref:
- return '<%s name=%r>' % (self.__class__.__name__, self.name)
+ return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
else:
- return GenericRepr(self, {'name': False, 'parameters': True,
+ return GenericRepr(self, {'mojom_name': False, 'parameters': True,
'response_parameters': True})
- def AddParameter(self, name, kind, ordinal=None, default=None,
+ def AddParameter(self, mojom_name, kind, ordinal=None, default=None,
attributes=None):
- parameter = Parameter(name, kind, ordinal, default, attributes)
+ parameter = Parameter(mojom_name, kind, ordinal, default, attributes)
self.parameters.append(parameter)
return parameter
- def AddResponseParameter(self, name, kind, ordinal=None, default=None,
+ def AddResponseParameter(self, mojom_name, kind, ordinal=None, default=None,
attributes=None):
if self.response_parameters == None:
self.response_parameters = []
- parameter = Parameter(name, kind, ordinal, default, attributes)
+ parameter = Parameter(mojom_name, kind, ordinal, default, attributes)
self.response_parameters.append(parameter)
return parameter
+ def Stylize(self, stylizer):
+ self.name = stylizer.StylizeMethod(self.mojom_name)
+ for param in self.parameters:
+ param.Stylize(stylizer)
+ if self.response_parameters is not None:
+ for param in self.response_parameters:
+ param.Stylize(stylizer)
+
+ if self.param_struct:
+ self.param_struct.Stylize(stylizer)
+ if self.response_param_struct:
+ self.response_param_struct.Stylize(stylizer)
+
@property
def min_version(self):
return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
@@ -551,40 +599,45 @@ class Method(object):
class Interface(ReferenceKind):
- ReferenceKind.AddSharedProperty('module')
+ ReferenceKind.AddSharedProperty('mojom_name')
ReferenceKind.AddSharedProperty('name')
- ReferenceKind.AddSharedProperty('imported_from')
ReferenceKind.AddSharedProperty('methods')
+ ReferenceKind.AddSharedProperty('enums')
+ ReferenceKind.AddSharedProperty('constants')
ReferenceKind.AddSharedProperty('attributes')
- def __init__(self, name=None, module=None, attributes=None):
- if name is not None:
- spec = 'x:' + name
+ def __init__(self, mojom_name=None, module=None, attributes=None):
+ if mojom_name is not None:
+ spec = 'x:' + mojom_name
else:
spec = None
- ReferenceKind.__init__(self, spec)
- self.module = module
- self.name = name
- self.imported_from = None
+ ReferenceKind.__init__(self, spec, False, module)
+ self.mojom_name = mojom_name
self.methods = []
+ self.enums = []
+ self.constants = []
self.attributes = attributes
def Repr(self, as_ref=True):
if as_ref:
- return '<%s name=%r>' % (self.__class__.__name__, self.name)
+ return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
else:
- return GenericRepr(self, {'name': False, 'attributes': False,
+ return GenericRepr(self, {'mojom_name': False, 'attributes': False,
'methods': False})
- def AddMethod(self, name, ordinal=None, attributes=None):
- method = Method(self, name, ordinal, attributes)
+ def AddMethod(self, mojom_name, ordinal=None, attributes=None):
+ method = Method(self, mojom_name, ordinal, attributes)
self.methods.append(method)
return method
- # TODO(451323): Remove when the language backends no longer rely on this.
- @property
- def client(self):
- return None
+ def Stylize(self, stylizer):
+ self.name = stylizer.StylizeInterface(self.mojom_name)
+ for method in self.methods:
+ method.Stylize(stylizer)
+ for enum in self.enums:
+ enum.Stylize(stylizer)
+ for constant in self.constants:
+ constant.Stylize(stylizer)
class AssociatedInterface(ReferenceKind):
@@ -603,13 +656,16 @@ class AssociatedInterface(ReferenceKind):
class EnumField(object):
- def __init__(self, name=None, value=None, attributes=None,
+ def __init__(self, mojom_name=None, value=None, attributes=None,
numeric_value=None):
- self.name = name
+ self.mojom_name = mojom_name
self.value = value
self.attributes = attributes
self.numeric_value = numeric_value
+ def Stylize(self, stylizer):
+ self.name = stylizer.StylizeEnumField(self.mojom_name)
+
@property
def min_version(self):
return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
@@ -617,24 +673,29 @@ class EnumField(object):
class Enum(Kind):
- def __init__(self, name=None, module=None, attributes=None):
- self.module = module
- self.name = name
+ def __init__(self, mojom_name=None, module=None, attributes=None):
+ self.mojom_name = mojom_name
self.native_only = False
- self.imported_from = None
- if name is not None:
- spec = 'x:' + name
+ if mojom_name is not None:
+ spec = 'x:' + mojom_name
else:
spec = None
- Kind.__init__(self, spec)
+ Kind.__init__(self, spec, module)
self.fields = []
self.attributes = attributes
+ self.min_value = None
+ self.max_value = None
def Repr(self, as_ref=True):
if as_ref:
- return '<%s name=%r>' % (self.__class__.__name__, self.name)
+ return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
else:
- return GenericRepr(self, {'name': False, 'fields': False})
+ return GenericRepr(self, {'mojom_name': False, 'fields': False})
+
+ def Stylize(self, stylizer):
+ self.name = stylizer.StylizeEnum(self.mojom_name)
+ for field in self.fields:
+ field.Stylize(stylizer)
@property
def extensible(self):
@@ -643,15 +704,18 @@ class Enum(Kind):
class Module(object):
- def __init__(self, name=None, namespace=None, attributes=None):
- self.name = name
- self.path = name
- self.namespace = namespace
+ def __init__(self, path=None, mojom_namespace=None,
+ attributes=None):
+ self.path = path
+ self.mojom_namespace = mojom_namespace
self.structs = []
self.unions = []
self.interfaces = []
+ self.enums = []
+ self.constants = []
self.kinds = {}
self.attributes = attributes
+ self.imports = []
def __repr__(self):
# Gives us a decent __repr__ for modules.
@@ -659,28 +723,44 @@ class Module(object):
def Repr(self, as_ref=True):
if as_ref:
- return '<%s name=%r namespace=%r>' % (
- self.__class__.__name__, self.name, self.namespace)
+ return '<%s path=%r mojom_namespace=%r>' % (
+ self.__class__.__name__, self.path, self.mojom_namespace)
else:
- return GenericRepr(self, {'name': False, 'namespace': False,
+ return GenericRepr(self, {'path': False, 'mojom_namespace': False,
'attributes': False, 'structs': False,
'interfaces': False, 'unions': False})
- def AddInterface(self, name, attributes=None):
- interface = Interface(name, self, attributes)
+ def AddInterface(self, mojom_name, attributes=None):
+ interface = Interface(mojom_name, self, attributes)
self.interfaces.append(interface)
return interface
- def AddStruct(self, name, attributes=None):
- struct = Struct(name, self, attributes)
+ def AddStruct(self, mojom_name, attributes=None):
+ struct = Struct(mojom_name, self, attributes)
self.structs.append(struct)
return struct
- def AddUnion(self, name, attributes=None):
- union = Union(name, self, attributes)
+ def AddUnion(self, mojom_name, attributes=None):
+ union = Union(mojom_name, self, attributes)
self.unions.append(union)
return union
+ def Stylize(self, stylizer):
+ self.namespace = stylizer.StylizeModule(self.mojom_namespace)
+ for struct in self.structs:
+ struct.Stylize(stylizer)
+ for union in self.unions:
+ union.Stylize(stylizer)
+ for interface in self.interfaces:
+ interface.Stylize(stylizer)
+ for enum in self.enums:
+ enum.Stylize(stylizer)
+ for constant in self.constants:
+ constant.Stylize(stylizer)
+
+ for imported_module in self.imports:
+ imported_module.Stylize(stylizer)
+
def IsBoolKind(kind):
return kind.spec == BOOL.spec
@@ -817,37 +897,57 @@ def HasCallbacks(interface):
# Finds out whether an interface passes associated interfaces and associated
# interface requests.
def PassesAssociatedKinds(interface):
- def _ContainsAssociatedKinds(kind, visited_kinds):
+ visited_kinds = set()
+ for method in interface.methods:
+ if MethodPassesAssociatedKinds(method, visited_kinds):
+ return True
+ return False
+
+
+def _AnyMethodParameterRecursive(method, predicate, visited_kinds=None):
+ def _HasProperty(kind):
if kind in visited_kinds:
# No need to examine the kind again.
return False
visited_kinds.add(kind)
- if IsAssociatedKind(kind):
+ if predicate(kind):
return True
if IsArrayKind(kind):
- return _ContainsAssociatedKinds(kind.kind, visited_kinds)
+ return _HasProperty(kind.kind)
if IsStructKind(kind) or IsUnionKind(kind):
for field in kind.fields:
- if _ContainsAssociatedKinds(field.kind, visited_kinds):
+ if _HasProperty(field.kind):
return True
if IsMapKind(kind):
- # No need to examine the key kind, only primitive kinds and non-nullable
- # string are allowed to be key kinds.
- return _ContainsAssociatedKinds(kind.value_kind, visited_kinds)
+ if _HasProperty(kind.key_kind) or _HasProperty(kind.value_kind):
+ return True
return False
- visited_kinds = set()
- for method in interface.methods:
- for param in method.parameters:
- if _ContainsAssociatedKinds(param.kind, visited_kinds):
+ if visited_kinds is None:
+ visited_kinds = set()
+
+ for param in method.parameters:
+ if _HasProperty(param.kind):
+ return True
+ if method.response_parameters != None:
+ for param in method.response_parameters:
+ if _HasProperty(param.kind):
return True
- if method.response_parameters != None:
- for param in method.response_parameters:
- if _ContainsAssociatedKinds(param.kind, visited_kinds):
- return True
return False
+# Finds out whether a method passes associated interfaces and associated
+# interface requests.
+def MethodPassesAssociatedKinds(method, visited_kinds=None):
+ return _AnyMethodParameterRecursive(method, IsAssociatedKind,
+ visited_kinds=visited_kinds)
+
+
+# Determines whether a method passes interfaces.
+def MethodPassesInterfaces(method):
+ return _AnyMethodParameterRecursive(method, IsInterfaceKind)
+
+
def HasSyncMethods(interface):
for method in interface.methods:
if method.sync:
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/pack.py b/mojo/public/tools/bindings/pylib/mojom/generate/pack.py
index 37dc8f396b..e4204a017d 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/pack.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/pack.py
@@ -56,7 +56,8 @@ class PackedField(object):
# TODO(mpcomplete): what about big enums?
return cls.kind_to_size[mojom.INT32]
if not kind in cls.kind_to_size:
- raise Exception("Invalid kind: %s" % kind.spec)
+ raise Exception("Undefined type: %s. Did you forget to import the file "
+ "containing the definition?" % kind.spec)
return cls.kind_to_size[kind]
@classmethod
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py b/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py
index 66f8954012..653a2dfc74 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py
@@ -4,27 +4,14 @@
# Based on third_party/WebKit/Source/build/scripts/template_expander.py.
-import imp
import os.path
import sys
-# Disable lint check for finding modules:
-# pylint: disable=F0401
-
-def _GetDirAbove(dirname):
- """Returns the directory "above" this file containing |dirname| (which must
- also be "above" this file)."""
- path = os.path.abspath(__file__)
- while True:
- path, tail = os.path.split(path)
- assert tail
- if tail == dirname:
- return path
-
-try:
- imp.find_module("jinja2")
-except ImportError:
- sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party"))
+_current_dir = os.path.dirname(os.path.realpath(__file__))
+# jinja2 is in chromium's 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] * 7 + ['third_party'])))
import jinja2
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/translate.py b/mojo/public/tools/bindings/pylib/mojom/generate/translate.py
index ffad7447a9..94fe2a6a52 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/translate.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/translate.py
@@ -10,20 +10,20 @@ representation of a mojom file. When called it's assumed that all imports have
already been parsed and converted to ASTs before.
"""
-import copy
+import os
import re
import module as mojom
from mojom.parse import ast
def _DuplicateName(values):
- """Returns the 'name' of the first entry in |values| whose 'name' has already
- been encountered. If there are no duplicates, returns None."""
+ """Returns the 'mojom_name' of the first entry in |values| whose 'mojom_name'
+ has already been encountered. If there are no duplicates, returns None."""
names = set()
for value in values:
- if value.name in names:
- return value.name
- names.add(value.name)
+ if value.mojom_name in names:
+ return value.mojom_name
+ names.add(value.mojom_name)
return None
def _ElemsOfType(elems, elem_type, scope):
@@ -121,36 +121,36 @@ def _LookupKind(kinds, spec, scope):
|scope| is a tuple that looks like (namespace, struct/interface), referring
to the location where the type is referenced."""
if spec.startswith('x:'):
- name = spec[2:]
+ mojom_name = spec[2:]
for i in xrange(len(scope), -1, -1):
test_spec = 'x:'
if i > 0:
test_spec += '.'.join(scope[:i]) + '.'
- test_spec += name
+ test_spec += mojom_name
kind = kinds.get(test_spec)
if kind:
return kind
return kinds.get(spec)
-def _LookupValue(values, name, scope, kind):
+def _LookupValue(values, mojom_name, scope, kind):
"""Like LookupKind, but for constant values."""
# If the type is an enum, the value can be specified as a qualified name, in
# which case the form EnumName.ENUM_VALUE must be used. We use the presence
# of a '.' in the requested name to identify this. Otherwise, we prepend the
# enum name.
- if isinstance(kind, mojom.Enum) and '.' not in name:
- name = '%s.%s' % (kind.spec.split(':', 1)[1], name)
+ if isinstance(kind, mojom.Enum) and '.' not in mojom_name:
+ mojom_name = '%s.%s' % (kind.spec.split(':', 1)[1], mojom_name)
for i in reversed(xrange(len(scope) + 1)):
test_spec = '.'.join(scope[:i])
if test_spec:
test_spec += '.'
- test_spec += name
+ test_spec += mojom_name
value = values.get(test_spec)
if value:
return value
- return values.get(name)
+ return values.get(mojom_name)
def _FixupExpression(module, value, scope, kind):
"""Translates an IDENTIFIER into a built-in value or structured NamedValue
@@ -222,41 +222,19 @@ def _Kind(kinds, spec, scope):
kinds[spec] = kind
return kind
-def _KindFromImport(original_kind, imported_from):
- """Used with 'import module' - clones the kind imported from the given
- module's namespace. Only used with Structs, Unions, Interfaces and Enums."""
- kind = copy.copy(original_kind)
- # |shared_definition| is used to store various properties (see
- # |AddSharedProperty()| in module.py), including |imported_from|. We don't
- # want the copy to share these with the original, so copy it if necessary.
- if hasattr(original_kind, 'shared_definition'):
- kind.shared_definition = copy.copy(original_kind.shared_definition)
- kind.imported_from = imported_from
- return kind
-
def _Import(module, import_module):
- import_item = {}
- import_item['module_name'] = import_module.name
- import_item['namespace'] = import_module.namespace
- import_item['module'] = import_module
-
# Copy the struct kinds from our imports into the current module.
importable_kinds = (mojom.Struct, mojom.Union, mojom.Enum, mojom.Interface)
for kind in import_module.kinds.itervalues():
if (isinstance(kind, importable_kinds) and
- kind.imported_from is None):
- kind = _KindFromImport(kind, import_item)
+ kind.module.path == import_module.path):
module.kinds[kind.spec] = kind
# Ditto for values.
for value in import_module.values.itervalues():
- if value.imported_from is None:
- # Values don't have shared definitions (since they're not nullable), so no
- # need to do anything special.
- value = copy.copy(value)
- value.imported_from = import_item
+ if value.module.path == import_module.path:
module.values[value.GetSpec()] = value
- return import_item
+ return import_module
def _Struct(module, parsed_struct):
"""
@@ -268,9 +246,9 @@ def _Struct(module, parsed_struct):
{mojom.Struct} AST struct.
"""
struct = mojom.Struct(module=module)
- struct.name = parsed_struct.name
+ struct.mojom_name = parsed_struct.mojom_name
struct.native_only = parsed_struct.body is None
- struct.spec = 'x:' + module.namespace + '.' + struct.name
+ struct.spec = 'x:' + module.mojom_namespace + '.' + struct.mojom_name
module.kinds[struct.spec] = struct
if struct.native_only:
struct.enums = []
@@ -279,13 +257,13 @@ def _Struct(module, parsed_struct):
else:
struct.enums = map(
lambda enum: _Enum(module, enum, struct),
- _ElemsOfType(parsed_struct.body, ast.Enum, parsed_struct.name))
+ _ElemsOfType(parsed_struct.body, ast.Enum, parsed_struct.mojom_name))
struct.constants = map(
lambda constant: _Constant(module, constant, struct),
- _ElemsOfType(parsed_struct.body, ast.Const, parsed_struct.name))
+ _ElemsOfType(parsed_struct.body, ast.Const, parsed_struct.mojom_name))
# Stash fields parsed_struct here temporarily.
struct.fields_data = _ElemsOfType(
- parsed_struct.body, ast.StructField, parsed_struct.name)
+ parsed_struct.body, ast.StructField, parsed_struct.mojom_name)
struct.attributes = _AttributeListToDict(parsed_struct.attribute_list)
# Enforce that a [Native] attribute is set to make native-only struct
@@ -295,6 +273,9 @@ def _Struct(module, parsed_struct):
raise Exception("Native-only struct declarations must include a " +
"Native attribute.")
+ if struct.attributes and struct.attributes.get('CustomSerializer', False):
+ struct.custom_serializer = True
+
return struct
def _Union(module, parsed_union):
@@ -307,12 +288,12 @@ def _Union(module, parsed_union):
{mojom.Union} AST union.
"""
union = mojom.Union(module=module)
- union.name = parsed_union.name
- union.spec = 'x:' + module.namespace + '.' + union.name
+ union.mojom_name = parsed_union.mojom_name
+ union.spec = 'x:' + module.mojom_namespace + '.' + union.mojom_name
module.kinds[union.spec] = union
# Stash fields parsed_union here temporarily.
union.fields_data = _ElemsOfType(
- parsed_union.body, ast.UnionField, parsed_union.name)
+ parsed_union.body, ast.UnionField, parsed_union.mojom_name)
union.attributes = _AttributeListToDict(parsed_union.attribute_list)
return union
@@ -327,14 +308,14 @@ def _StructField(module, parsed_field, struct):
{mojom.StructField} AST struct field.
"""
field = mojom.StructField()
- field.name = parsed_field.name
+ field.mojom_name = parsed_field.mojom_name
field.kind = _Kind(
module.kinds, _MapKind(parsed_field.typename),
- (module.namespace, struct.name))
+ (module.mojom_namespace, struct.mojom_name))
field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None
field.default = _FixupExpression(
- module, parsed_field.default_value, (module.namespace, struct.name),
- field.kind)
+ module, parsed_field.default_value,
+ (module.mojom_namespace, struct.mojom_name), field.kind)
field.attributes = _AttributeListToDict(parsed_field.attribute_list)
return field
@@ -349,13 +330,13 @@ def _UnionField(module, parsed_field, union):
{mojom.UnionField} AST union.
"""
field = mojom.UnionField()
- field.name = parsed_field.name
+ field.mojom_name = parsed_field.mojom_name
field.kind = _Kind(
module.kinds, _MapKind(parsed_field.typename),
- (module.namespace, union.name))
+ (module.mojom_namespace, union.mojom_name))
field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None
field.default = _FixupExpression(
- module, None, (module.namespace, union.name), field.kind)
+ module, None, (module.mojom_namespace, union.mojom_name), field.kind)
field.attributes = _AttributeListToDict(parsed_field.attribute_list)
return field
@@ -370,10 +351,10 @@ def _Parameter(module, parsed_param, interface):
{mojom.Parameter} AST parameter.
"""
parameter = mojom.Parameter()
- parameter.name = parsed_param.name
+ parameter.mojom_name = parsed_param.mojom_name
parameter.kind = _Kind(
module.kinds, _MapKind(parsed_param.typename),
- (module.namespace, interface.name))
+ (module.mojom_namespace, interface.mojom_name))
parameter.ordinal = (
parsed_param.ordinal.value if parsed_param.ordinal else None)
parameter.default = None # TODO(tibell): We never have these. Remove field?
@@ -391,7 +372,7 @@ def _Method(module, parsed_method, interface):
{mojom.Method} AST method.
"""
method = mojom.Method(
- interface, parsed_method.name,
+ interface, parsed_method.mojom_name,
ordinal=parsed_method.ordinal.value if parsed_method.ordinal else None)
method.parameters = map(
lambda parameter: _Parameter(module, parameter, interface),
@@ -421,18 +402,18 @@ def _Interface(module, parsed_iface):
{mojom.Interface} AST interface.
"""
interface = mojom.Interface(module=module)
- interface.name = parsed_iface.name
- interface.spec = 'x:' + module.namespace + '.' + interface.name
+ interface.mojom_name = parsed_iface.mojom_name
+ interface.spec = 'x:' + module.mojom_namespace + '.' + interface.mojom_name
module.kinds[interface.spec] = interface
interface.enums = map(
lambda enum: _Enum(module, enum, interface),
- _ElemsOfType(parsed_iface.body, ast.Enum, parsed_iface.name))
+ _ElemsOfType(parsed_iface.body, ast.Enum, parsed_iface.mojom_name))
interface.constants = map(
lambda constant: _Constant(module, constant, interface),
- _ElemsOfType(parsed_iface.body, ast.Const, parsed_iface.name))
+ _ElemsOfType(parsed_iface.body, ast.Const, parsed_iface.mojom_name))
# Stash methods parsed_iface here temporarily.
interface.methods_data = _ElemsOfType(
- parsed_iface.body, ast.Method, parsed_iface.name)
+ parsed_iface.body, ast.Method, parsed_iface.mojom_name)
interface.attributes = _AttributeListToDict(parsed_iface.attribute_list)
return interface
@@ -448,17 +429,18 @@ def _EnumField(module, enum, parsed_field, parent_kind):
{mojom.EnumField} AST enum field.
"""
field = mojom.EnumField()
- field.name = parsed_field.name
+ field.mojom_name = parsed_field.mojom_name
# TODO(mpcomplete): FixupExpression should be done in the second pass,
# so constants and enums can refer to each other.
# TODO(mpcomplete): But then, what if constants are initialized to an enum? Or
# vice versa?
if parent_kind:
field.value = _FixupExpression(
- module, parsed_field.value, (module.namespace, parent_kind.name), enum)
+ module, parsed_field.value,
+ (module.mojom_namespace, parent_kind.mojom_name), enum)
else:
field.value = _FixupExpression(
- module, parsed_field.value, (module.namespace, ), enum)
+ module, parsed_field.value, (module.mojom_namespace, ), enum)
field.attributes = _AttributeListToDict(parsed_field.attribute_list)
value = mojom.EnumValue(module, enum, field)
module.values[value.GetSpec()] = value
@@ -468,11 +450,17 @@ def _ResolveNumericEnumValues(enum_fields):
"""
Given a reference to a list of mojom.EnumField, resolves and assigns their
values to EnumField.numeric_value.
+
+ Returns:
+ A tuple of the lowest and highest assigned enumerator value or None, None
+ if no enumerator values were assigned.
"""
- # map of <name> -> integral value
+ # map of <mojom_name> -> integral value
resolved_enum_values = {}
prev_value = -1
+ min_value = None
+ max_value = None
for field in enum_fields:
# This enum value is +1 the previous enum value (e.g: BEGIN).
if field.value is None:
@@ -484,12 +472,18 @@ def _ResolveNumericEnumValues(enum_fields):
# Reference to a previous enum value (e.g: INIT = BEGIN).
elif type(field.value) is mojom.EnumValue:
- prev_value = resolved_enum_values[field.value.name]
+ prev_value = resolved_enum_values[field.value.mojom_name]
else:
raise Exception("Unresolved enum value.")
- resolved_enum_values[field.name] = prev_value
+ resolved_enum_values[field.mojom_name] = prev_value
field.numeric_value = prev_value
+ if min_value is None or prev_value < min_value:
+ min_value = prev_value
+ if max_value is None or prev_value > max_value:
+ max_value = prev_value
+
+ return min_value, max_value
def _Enum(module, parsed_enum, parent_kind):
"""
@@ -501,21 +495,19 @@ def _Enum(module, parsed_enum, parent_kind):
{mojom.Enum} AST enum.
"""
enum = mojom.Enum(module=module)
- enum.name = parsed_enum.name
+ enum.mojom_name = parsed_enum.mojom_name
enum.native_only = parsed_enum.enum_value_list is None
- name = enum.name
+ mojom_name = enum.mojom_name
if parent_kind:
- name = parent_kind.name + '.' + name
- enum.spec = 'x:%s.%s' % (module.namespace, name)
+ mojom_name = parent_kind.mojom_name + '.' + mojom_name
+ enum.spec = 'x:%s.%s' % (module.mojom_namespace, mojom_name)
enum.parent_kind = parent_kind
enum.attributes = _AttributeListToDict(parsed_enum.attribute_list)
- if enum.native_only:
- enum.fields = []
- else:
+ if not enum.native_only:
enum.fields = map(
lambda field: _EnumField(module, enum, field, parent_kind),
parsed_enum.enum_value_list)
- _ResolveNumericEnumValues(enum.fields)
+ enum.min_value, enum.max_value = _ResolveNumericEnumValues(enum.fields)
module.kinds[enum.spec] = enum
@@ -538,11 +530,11 @@ def _Constant(module, parsed_const, parent_kind):
{mojom.Constant} AST constant.
"""
constant = mojom.Constant()
- constant.name = parsed_const.name
+ constant.mojom_name = parsed_const.mojom_name
if parent_kind:
- scope = (module.namespace, parent_kind.name)
+ scope = (module.mojom_namespace, parent_kind.mojom_name)
else:
- scope = (module.namespace, )
+ scope = (module.mojom_namespace, )
# TODO(mpcomplete): maybe we should only support POD kinds.
constant.kind = _Kind(module.kinds, _MapKind(parsed_const.typename), scope)
constant.parent_kind = parent_kind
@@ -552,26 +544,25 @@ def _Constant(module, parsed_const, parent_kind):
module.values[value.GetSpec()] = value
return constant
-def _Module(tree, name, imports):
+def _Module(tree, path, imports):
"""
Args:
tree: {ast.Mojom} The parse tree.
- name: {str} The mojom filename, excluding the path.
+ path: {str} The path to the mojom file.
imports: {Dict[str, mojom.Module]} Mapping from filenames, as they appear in
the import list, to already processed modules. Used to process imports.
Returns:
{mojom.Module} An AST for the mojom.
"""
- module = mojom.Module()
+ module = mojom.Module(path=path)
module.kinds = {}
for kind in mojom.PRIMITIVES:
module.kinds[kind.spec] = kind
module.values = {}
- module.name = name
- module.namespace = tree.module.name[1] if tree.module else ''
+ module.mojom_namespace = tree.module.mojom_namespace[1] if tree.module else ''
# Imports must come first, because they add to module.kinds which is used
# by by the others.
module.imports = [
@@ -583,22 +574,23 @@ def _Module(tree, name, imports):
module.attributes = dict((attribute.key, attribute.value)
for attribute in tree.module.attribute_list)
+ filename = os.path.basename(path)
# First pass collects kinds.
module.enums = map(
lambda enum: _Enum(module, enum, None),
- _ElemsOfType(tree.definition_list, ast.Enum, name))
+ _ElemsOfType(tree.definition_list, ast.Enum, filename))
module.structs = map(
lambda struct: _Struct(module, struct),
- _ElemsOfType(tree.definition_list, ast.Struct, name))
+ _ElemsOfType(tree.definition_list, ast.Struct, filename))
module.unions = map(
lambda union: _Union(module, union),
- _ElemsOfType(tree.definition_list, ast.Union, name))
+ _ElemsOfType(tree.definition_list, ast.Union, filename))
module.interfaces = map(
lambda interface: _Interface(module, interface),
- _ElemsOfType(tree.definition_list, ast.Interface, name))
+ _ElemsOfType(tree.definition_list, ast.Interface, filename))
module.constants = map(
lambda constant: _Constant(module, constant, None),
- _ElemsOfType(tree.definition_list, ast.Const, name))
+ _ElemsOfType(tree.definition_list, ast.Const, filename))
# Second pass expands fields and methods. This allows fields and parameters
# to refer to kinds defined anywhere in the mojom.
@@ -617,23 +609,17 @@ def _Module(tree, name, imports):
return module
-def OrderedModule(tree, name, imports):
+def OrderedModule(tree, path, imports):
"""Convert parse tree to AST module.
Args:
tree: {ast.Mojom} The parse tree.
- name: {str} The mojom filename, excluding the path.
+ path: {str} The path to the mojom file.
imports: {Dict[str, mojom.Module]} Mapping from filenames, as they appear in
the import list, to already processed modules. Used to process imports.
Returns:
{mojom.Module} An AST for the mojom.
"""
- module = _Module(tree, name, imports)
- for interface in module.interfaces:
- next_ordinal = 0
- for method in interface.methods:
- if method.ordinal is None:
- method.ordinal = next_ordinal
- next_ordinal = method.ordinal + 1
+ module = _Module(tree, path, imports)
return module
diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/ast.py b/mojo/public/tools/bindings/pylib/mojom/parse/ast.py
index 2c6b5fcdf8..e9d7844986 100644
--- a/mojo/public/tools/bindings/pylib/mojom/parse/ast.py
+++ b/mojo/public/tools/bindings/pylib/mojom/parse/ast.py
@@ -84,10 +84,10 @@ class Definition(NodeBase):
enum values, consts, structs, struct fields, interfaces). (This does not
include parameter definitions.) This class is meant to be subclassed."""
- def __init__(self, name, **kwargs):
- assert isinstance(name, str)
+ def __init__(self, mojom_name, **kwargs):
+ assert isinstance(mojom_name, str)
NodeBase.__init__(self, **kwargs)
- self.name = name
+ self.mojom_name = mojom_name
################################################################################
@@ -117,18 +117,21 @@ class AttributeList(NodeListBase):
class Const(Definition):
"""Represents a const definition."""
- def __init__(self, name, typename, value, **kwargs):
+ def __init__(self, mojom_name, attribute_list, typename, value, **kwargs):
+ assert attribute_list is None or isinstance(attribute_list, AttributeList)
# The typename is currently passed through as a string.
assert isinstance(typename, str)
# The value is either a literal (currently passed through as a string) or a
# "wrapped identifier".
assert isinstance(value, str) or isinstance(value, tuple)
- super(Const, self).__init__(name, **kwargs)
+ super(Const, self).__init__(mojom_name, **kwargs)
+ self.attribute_list = attribute_list
self.typename = typename
self.value = value
def __eq__(self, other):
return super(Const, self).__eq__(other) and \
+ self.attribute_list == other.attribute_list and \
self.typename == other.typename and \
self.value == other.value
@@ -136,10 +139,10 @@ class Const(Definition):
class Enum(Definition):
"""Represents an enum definition."""
- def __init__(self, name, attribute_list, enum_value_list, **kwargs):
+ def __init__(self, mojom_name, attribute_list, enum_value_list, **kwargs):
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert enum_value_list is None or isinstance(enum_value_list, EnumValueList)
- super(Enum, self).__init__(name, **kwargs)
+ super(Enum, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.enum_value_list = enum_value_list
@@ -152,12 +155,12 @@ class Enum(Definition):
class EnumValue(Definition):
"""Represents a definition of an enum value."""
- def __init__(self, name, attribute_list, value, **kwargs):
+ def __init__(self, mojom_name, attribute_list, value, **kwargs):
# The optional value is either an int (which is current a string) or a
# "wrapped identifier".
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert value is None or isinstance(value, (str, tuple))
- super(EnumValue, self).__init__(name, **kwargs)
+ super(EnumValue, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.value = value
@@ -177,13 +180,16 @@ class EnumValueList(NodeListBase):
class Import(NodeBase):
"""Represents an import statement."""
- def __init__(self, import_filename, **kwargs):
+ def __init__(self, attribute_list, import_filename, **kwargs):
+ assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert isinstance(import_filename, str)
super(Import, self).__init__(**kwargs)
+ self.attribute_list = attribute_list
self.import_filename = import_filename
def __eq__(self, other):
return super(Import, self).__eq__(other) and \
+ self.attribute_list == other.attribute_list and \
self.import_filename == other.import_filename
@@ -196,10 +202,10 @@ class ImportList(NodeListBase):
class Interface(Definition):
"""Represents an interface definition."""
- def __init__(self, name, attribute_list, body, **kwargs):
+ def __init__(self, mojom_name, attribute_list, body, **kwargs):
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert isinstance(body, InterfaceBody)
- super(Interface, self).__init__(name, **kwargs)
+ super(Interface, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.body = body
@@ -212,14 +218,14 @@ class Interface(Definition):
class Method(Definition):
"""Represents a method definition."""
- def __init__(self, name, attribute_list, ordinal, parameter_list,
+ def __init__(self, mojom_name, attribute_list, ordinal, parameter_list,
response_parameter_list, **kwargs):
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
assert isinstance(parameter_list, ParameterList)
assert response_parameter_list is None or \
isinstance(response_parameter_list, ParameterList)
- super(Method, self).__init__(name, **kwargs)
+ super(Method, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.ordinal = ordinal
self.parameter_list = parameter_list
@@ -243,17 +249,17 @@ class InterfaceBody(NodeListBase):
class Module(NodeBase):
"""Represents a module statement."""
- def __init__(self, name, attribute_list, **kwargs):
- # |name| is either none or a "wrapped identifier".
- assert name is None or isinstance(name, tuple)
+ def __init__(self, mojom_namespace, attribute_list, **kwargs):
+ # |mojom_namespace| is either none or a "wrapped identifier".
+ assert mojom_namespace is None or isinstance(mojom_namespace, tuple)
assert attribute_list is None or isinstance(attribute_list, AttributeList)
super(Module, self).__init__(**kwargs)
- self.name = name
+ self.mojom_namespace = mojom_namespace
self.attribute_list = attribute_list
def __eq__(self, other):
return super(Module, self).__eq__(other) and \
- self.name == other.name and \
+ self.mojom_namespace == other.mojom_namespace and \
self.attribute_list == other.attribute_list
@@ -296,20 +302,20 @@ class Ordinal(NodeBase):
class Parameter(NodeBase):
"""Represents a method request or response parameter."""
- def __init__(self, name, attribute_list, ordinal, typename, **kwargs):
- assert isinstance(name, str)
+ def __init__(self, mojom_name, attribute_list, ordinal, typename, **kwargs):
+ assert isinstance(mojom_name, str)
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
assert isinstance(typename, str)
super(Parameter, self).__init__(**kwargs)
- self.name = name
+ self.mojom_name = mojom_name
self.attribute_list = attribute_list
self.ordinal = ordinal
self.typename = typename
def __eq__(self, other):
return super(Parameter, self).__eq__(other) and \
- self.name == other.name and \
+ self.mojom_name == other.mojom_name and \
self.attribute_list == other.attribute_list and \
self.ordinal == other.ordinal and \
self.typename == other.typename
@@ -324,10 +330,10 @@ class ParameterList(NodeListBase):
class Struct(Definition):
"""Represents a struct definition."""
- def __init__(self, name, attribute_list, body, **kwargs):
+ def __init__(self, mojom_name, attribute_list, body, **kwargs):
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert isinstance(body, StructBody) or body is None
- super(Struct, self).__init__(name, **kwargs)
+ super(Struct, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.body = body
@@ -340,16 +346,16 @@ class Struct(Definition):
class StructField(Definition):
"""Represents a struct field definition."""
- def __init__(self, name, attribute_list, ordinal, typename, default_value,
- **kwargs):
- assert isinstance(name, str)
+ def __init__(self, mojom_name, attribute_list, ordinal, typename,
+ default_value, **kwargs):
+ assert isinstance(mojom_name, str)
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
assert isinstance(typename, str)
# The optional default value is currently either a value as a string or a
# "wrapped identifier".
assert default_value is None or isinstance(default_value, (str, tuple))
- super(StructField, self).__init__(name, **kwargs)
+ super(StructField, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.ordinal = ordinal
self.typename = typename
@@ -373,10 +379,10 @@ class StructBody(NodeListBase):
class Union(Definition):
"""Represents a union definition."""
- def __init__(self, name, attribute_list, body, **kwargs):
+ def __init__(self, mojom_name, attribute_list, body, **kwargs):
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert isinstance(body, UnionBody)
- super(Union, self).__init__(name, **kwargs)
+ super(Union, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.body = body
@@ -388,12 +394,12 @@ class Union(Definition):
class UnionField(Definition):
- def __init__(self, name, attribute_list, ordinal, typename, **kwargs):
- assert isinstance(name, str)
+ def __init__(self, mojom_name, attribute_list, ordinal, typename, **kwargs):
+ assert isinstance(mojom_name, str)
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
assert isinstance(typename, str)
- super(UnionField, self).__init__(name, **kwargs)
+ super(UnionField, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.ordinal = ordinal
self.typename = typename
diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/conditional_features.py b/mojo/public/tools/bindings/pylib/mojom/parse/conditional_features.py
new file mode 100644
index 0000000000..c2279cfc55
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/parse/conditional_features.py
@@ -0,0 +1,80 @@
+# Copyright 2018 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.
+
+"""Helpers for processing conditionally enabled features in a mojom."""
+
+from . import ast
+from ..error import Error
+
+class EnableIfError(Error):
+ """ Class for errors from ."""
+
+ def __init__(self, filename, message, lineno=None):
+ Error.__init__(self, filename, message, lineno=lineno, addenda=None)
+
+def _IsEnabled(definition, enabled_features):
+ """Returns true if a definition is enabled.
+
+ A definition is enabled if it has no EnableIf attribute, or if the value of
+ the EnableIf attribute is in enabled_features.
+ """
+ if not hasattr(definition, "attribute_list"):
+ return True
+ if not definition.attribute_list:
+ return True
+
+ already_defined = False
+ for a in definition.attribute_list:
+ if a.key == 'EnableIf':
+ if already_defined:
+ raise EnableIfError(definition.filename,
+ "EnableIf attribute may only be defined once per field.",
+ definition.lineno)
+ already_defined = True
+
+ for attribute in definition.attribute_list:
+ if attribute.key == 'EnableIf' and attribute.value not in enabled_features:
+ return False
+ return True
+
+
+def _FilterDisabledFromNodeList(node_list, enabled_features):
+ if not node_list:
+ return
+ assert isinstance(node_list, ast.NodeListBase)
+ node_list.items = [
+ item for item in node_list.items if _IsEnabled(item, enabled_features)
+ ]
+ for item in node_list.items:
+ _FilterDefinition(item, enabled_features)
+
+
+def _FilterDefinition(definition, enabled_features):
+ """Filters definitions with a body."""
+ if isinstance(definition, ast.Enum):
+ _FilterDisabledFromNodeList(definition.enum_value_list, enabled_features)
+ elif isinstance(definition, ast.Interface):
+ _FilterDisabledFromNodeList(definition.body, enabled_features)
+ elif isinstance(definition, ast.Method):
+ _FilterDisabledFromNodeList(definition.parameter_list, enabled_features)
+ _FilterDisabledFromNodeList(definition.response_parameter_list,
+ enabled_features)
+ elif isinstance(definition, ast.Struct):
+ _FilterDisabledFromNodeList(definition.body, enabled_features)
+ elif isinstance(definition, ast.Union):
+ _FilterDisabledFromNodeList(definition.body, enabled_features)
+
+
+def RemoveDisabledDefinitions(mojom, enabled_features):
+ """Removes conditionally disabled definitions from a Mojom node."""
+ mojom.import_list = ast.ImportList([
+ imported_file for imported_file in mojom.import_list
+ if _IsEnabled(imported_file, enabled_features)
+ ])
+ mojom.definition_list = [
+ definition for definition in mojom.definition_list
+ if _IsEnabled(definition, enabled_features)
+ ]
+ for definition in mojom.definition_list:
+ _FilterDefinition(definition, enabled_features)
diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/parser.py b/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
index 868fb45f33..b9f10dce9e 100644
--- a/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
+++ b/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
@@ -4,24 +4,12 @@
"""Generates a syntax tree from a Mojo IDL file."""
-import imp
import os.path
import sys
-def _GetDirAbove(dirname):
- """Returns the directory "above" this file containing |dirname| (which must
- also be "above" this file)."""
- path = os.path.abspath(__file__)
- while True:
- path, tail = os.path.split(path)
- assert tail
- if tail == dirname:
- return path
-
-try:
- imp.find_module("ply")
-except ImportError:
- sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party"))
+_current_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.insert(
+ 1, os.path.join(_current_dir, *([os.pardir] * 7 + ['third_party'])))
from ply import lex
from ply import yacc
@@ -103,10 +91,11 @@ class Parser(object):
p[0].definition_list.append(p[2])
def p_import(self, p):
- """import : IMPORT STRING_LITERAL SEMI"""
+ """import : attribute_section IMPORT STRING_LITERAL SEMI"""
# 'eval' the literal to strip the quotes.
# TODO(vtl): This eval is dubious. We should unquote/unescape ourselves.
- p[0] = ast.Import(eval(p[2]), filename=self.filename, lineno=p.lineno(2))
+ p[0] = ast.Import(p[1], eval(p[3]), filename=self.filename,
+ lineno=p.lineno(2))
def p_module(self, p):
"""module : attribute_section MODULE identifier_wrapped SEMI"""
@@ -383,8 +372,8 @@ class Parser(object):
filename=self.filename, lineno=p.lineno(2))
def p_const(self, p):
- """const : CONST typename NAME EQUALS constant SEMI"""
- p[0] = ast.Const(p[3], p[2], p[5])
+ """const : attribute_section CONST typename NAME EQUALS constant SEMI"""
+ p[0] = ast.Const(p[4], p[1], p[3], p[6])
def p_constant(self, p):
"""constant : literal
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/generate/generator_unittest.py b/mojo/public/tools/bindings/pylib/mojom_tests/generate/generator_unittest.py
index a684773719..e037c963b4 100644
--- a/mojo/public/tools/bindings/pylib/mojom_tests/generate/generator_unittest.py
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/generate/generator_unittest.py
@@ -27,10 +27,14 @@ from mojom.generate import generator
class StringManipulationTest(unittest.TestCase):
"""generator contains some string utilities, this tests only those."""
- def testUnderToCamel(self):
- """Tests UnderToCamel which converts underscore_separated to CamelCase."""
- self.assertEquals("CamelCase", generator.UnderToCamel("camel_case"))
- self.assertEquals("CamelCase", generator.UnderToCamel("CAMEL_CASE"))
+ def testToCamel(self):
+ self.assertEquals("CamelCase", generator.ToCamel("camel_case"))
+ self.assertEquals("CAMELCASE", generator.ToCamel("CAMEL_CASE"))
+ self.assertEquals("camelCase", generator.ToCamel("camel_case",
+ lower_initial=True))
+ self.assertEquals("CamelCase", generator.ToCamel("camel case",
+ dilimiter=' '))
+ self.assertEquals("CaMelCaSe", generator.ToCamel("caMel_caSe"))
if __name__ == "__main__":
unittest.main()
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/parse/conditional_features_unittest.py b/mojo/public/tools/bindings/pylib/mojom_tests/parse/conditional_features_unittest.py
new file mode 100644
index 0000000000..4d5838823f
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/parse/conditional_features_unittest.py
@@ -0,0 +1,232 @@
+# Copyright 2018 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.
+
+import imp
+import os
+import sys
+import unittest
+
+
+def _GetDirAbove(dirname):
+ """Returns the directory "above" this file containing |dirname| (which must
+ also be "above" this file)."""
+ path = os.path.abspath(__file__)
+ while True:
+ path, tail = os.path.split(path)
+ assert tail
+ if tail == dirname:
+ return path
+
+
+try:
+ imp.find_module('mojom')
+except ImportError:
+ sys.path.append(os.path.join(_GetDirAbove('pylib'), 'pylib'))
+import mojom.parse.ast as ast
+import mojom.parse.conditional_features as conditional_features
+import mojom.parse.parser as parser
+
+ENABLED_FEATURES = frozenset({'red', 'green', 'blue'})
+
+
+class ConditionalFeaturesTest(unittest.TestCase):
+ """Tests |mojom.parse.conditional_features|."""
+
+ def parseAndAssertEqual(self, source, expected_source):
+ definition = parser.Parse(source, "my_file.mojom")
+ conditional_features.RemoveDisabledDefinitions(definition, ENABLED_FEATURES)
+ expected = parser.Parse(expected_source, "my_file.mojom")
+ self.assertEquals(definition, expected)
+
+ def testFilterConst(self):
+ """Test that Consts are correctly filtered."""
+ const_source = """
+ [EnableIf=blue]
+ const int kMyConst1 = 1;
+ [EnableIf=orange]
+ const double kMyConst2 = 2;
+ const int kMyConst3 = 3;
+ """
+ expected_source = """
+ [EnableIf=blue]
+ const int kMyConst1 = 1;
+ const int kMyConst3 = 3;
+ """
+ self.parseAndAssertEqual(const_source, expected_source)
+
+ def testFilterEnum(self):
+ """Test that EnumValues are correctly filtered from an Enum."""
+ enum_source = """
+ enum MyEnum {
+ [EnableIf=purple]
+ VALUE1,
+ [EnableIf=blue]
+ VALUE2,
+ VALUE3,
+ };
+ """
+ expected_source = """
+ enum MyEnum {
+ [EnableIf=blue]
+ VALUE2,
+ VALUE3
+ };
+ """
+ self.parseAndAssertEqual(enum_source, expected_source)
+
+ def testFilterImport(self):
+ """Test that imports are correctly filtered from a Mojom."""
+ import_source = """
+ [EnableIf=blue]
+ import "foo.mojom";
+ import "bar.mojom";
+ [EnableIf=purple]
+ import "baz.mojom";
+ """
+ expected_source = """
+ [EnableIf=blue]
+ import "foo.mojom";
+ import "bar.mojom";
+ """
+ self.parseAndAssertEqual(import_source, expected_source)
+
+ def testFilterInterface(self):
+ """Test that definitions are correctly filtered from an Interface."""
+ interface_source = """
+ interface MyInterface {
+ [EnableIf=blue]
+ enum MyEnum {
+ [EnableIf=purple]
+ VALUE1,
+ VALUE2,
+ };
+ [EnableIf=blue]
+ const int32 kMyConst = 123;
+ [EnableIf=purple]
+ MyMethod();
+ };
+ """
+ expected_source = """
+ interface MyInterface {
+ [EnableIf=blue]
+ enum MyEnum {
+ VALUE2,
+ };
+ [EnableIf=blue]
+ const int32 kMyConst = 123;
+ };
+ """
+ self.parseAndAssertEqual(interface_source, expected_source)
+
+ def testFilterMethod(self):
+ """Test that Parameters are correctly filtered from a Method."""
+ method_source = """
+ interface MyInterface {
+ [EnableIf=blue]
+ MyMethod([EnableIf=purple] int32 a) => ([EnableIf=red] int32 b);
+ };
+ """
+ expected_source = """
+ interface MyInterface {
+ [EnableIf=blue]
+ MyMethod() => ([EnableIf=red] int32 b);
+ };
+ """
+ self.parseAndAssertEqual(method_source, expected_source)
+
+ def testFilterStruct(self):
+ """Test that definitions are correctly filtered from a Struct."""
+ struct_source = """
+ struct MyStruct {
+ [EnableIf=blue]
+ enum MyEnum {
+ VALUE1,
+ [EnableIf=purple]
+ VALUE2,
+ };
+ [EnableIf=yellow]
+ const double kMyConst = 1.23;
+ [EnableIf=green]
+ int32 a;
+ double b;
+ [EnableIf=purple]
+ int32 c;
+ [EnableIf=blue]
+ double d;
+ int32 e;
+ [EnableIf=orange]
+ double f;
+ };
+ """
+ expected_source = """
+ struct MyStruct {
+ [EnableIf=blue]
+ enum MyEnum {
+ VALUE1,
+ };
+ [EnableIf=green]
+ int32 a;
+ double b;
+ [EnableIf=blue]
+ double d;
+ int32 e;
+ };
+ """
+ self.parseAndAssertEqual(struct_source, expected_source)
+
+ def testFilterUnion(self):
+ """Test that UnionFields are correctly filtered from a Union."""
+ union_source = """
+ union MyUnion {
+ [EnableIf=yellow]
+ int32 a;
+ [EnableIf=red]
+ bool b;
+ };
+ """
+ expected_source = """
+ union MyUnion {
+ [EnableIf=red]
+ bool b;
+ };
+ """
+ self.parseAndAssertEqual(union_source, expected_source)
+
+ def testSameNameFields(self):
+ mojom_source = """
+ enum Foo {
+ [EnableIf=red]
+ VALUE1 = 5,
+ [EnableIf=yellow]
+ VALUE1 = 6,
+ };
+ [EnableIf=red]
+ const double kMyConst = 1.23;
+ [EnableIf=yellow]
+ const double kMyConst = 4.56;
+ """
+ expected_source = """
+ enum Foo {
+ [EnableIf=red]
+ VALUE1 = 5,
+ };
+ [EnableIf=red]
+ const double kMyConst = 1.23;
+ """
+ self.parseAndAssertEqual(mojom_source, expected_source)
+
+ def testMultipleEnableIfs(self):
+ source = """
+ enum Foo {
+ [EnableIf=red,EnableIf=yellow]
+ kBarValue = 5,
+ };
+ """
+ definition = parser.Parse(source, "my_file.mojom")
+ self.assertRaises(conditional_features.EnableIfError,
+ conditional_features.RemoveDisabledDefinitions,
+ definition, ENABLED_FEATURES)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py b/mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py
index 6822cbc8d0..36d8c4abfe 100644
--- a/mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py
@@ -17,10 +17,7 @@ def _GetDirAbove(dirname):
if tail == dirname:
return path
-try:
- imp.find_module("ply")
-except ImportError:
- sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party"))
+sys.path.insert(1, os.path.join(_GetDirAbove("mojo"), "third_party"))
from ply import lex
try:
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py b/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py
index 3f4ca871e3..b156bb71ba 100644
--- a/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py
@@ -192,7 +192,7 @@ class ParserTest(unittest.TestCase):
None,
ast.EnumValueList(
ast.EnumValue('VALUE', None, None))),
- ast.Const('kMyConst', 'double', '1.23'),
+ ast.Const('kMyConst', None, 'double', '1.23'),
ast.StructField('a', None, None, 'int32', None),
ast.StructField('b', None, None, 'SomeOtherStruct', None)]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
@@ -409,7 +409,7 @@ class ParserTest(unittest.TestCase):
[ast.Struct(
'MyStruct', None,
ast.StructBody(
- [ast.Const('kNumber', 'int8', '-1'),
+ [ast.Const('kNumber', None, 'int8', '-1'),
ast.StructField('number', None, ast.Ordinal(0), 'int8',
('IDENTIFIER', 'kNumber'))]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
@@ -897,7 +897,7 @@ class ParserTest(unittest.TestCase):
None,
ast.EnumValueList(
ast.EnumValue('VALUE', None, None))),
- ast.Const('kMyConst', 'int32', '123'),
+ ast.Const('kMyConst', None, 'int32', '123'),
ast.Method(
'MyMethod',
None,
@@ -990,61 +990,71 @@ class ParserTest(unittest.TestCase):
source4 = """\
[Attr0=0] module my_module;
- [Attr1=1] struct MyStruct {
- [Attr2=2] int32 a;
+ [Attr1=1] import "my_import";
+
+ [Attr2=2] struct MyStruct {
+ [Attr3=3] int32 a;
};
- [Attr3=3] union MyUnion {
- [Attr4=4] int32 a;
+ [Attr4=4] union MyUnion {
+ [Attr5=5] int32 a;
};
- [Attr5=5] enum MyEnum {
- [Attr6=6] a
+ [Attr6=6] enum MyEnum {
+ [Attr7=7] a
};
- [Attr7=7] interface MyInterface {
- [Attr8=8] MyMethod([Attr9=9] int32 a) => ([Attr10=10] bool b);
+ [Attr8=8] interface MyInterface {
+ [Attr9=9] MyMethod([Attr10=10] int32 a) => ([Attr11=11] bool b);
};
+ [Attr12=12] const double kMyConst = 1.23;
"""
expected4 = ast.Mojom(
ast.Module(('IDENTIFIER', 'my_module'),
ast.AttributeList([ast.Attribute("Attr0", 0)])),
- ast.ImportList(),
+ ast.ImportList(ast.Import(
+ ast.AttributeList([ast.Attribute("Attr1", 1)]),
+ "my_import")),
[ast.Struct(
'MyStruct',
- ast.AttributeList(ast.Attribute("Attr1", 1)),
+ ast.AttributeList(ast.Attribute("Attr2", 2)),
ast.StructBody(
ast.StructField(
- 'a', ast.AttributeList([ast.Attribute("Attr2", 2)]),
+ 'a', ast.AttributeList([ast.Attribute("Attr3", 3)]),
None, 'int32', None))),
ast.Union(
'MyUnion',
- ast.AttributeList(ast.Attribute("Attr3", 3)),
+ ast.AttributeList(ast.Attribute("Attr4", 4)),
ast.UnionBody(
ast.UnionField(
- 'a', ast.AttributeList([ast.Attribute("Attr4", 4)]), None,
+ 'a', ast.AttributeList([ast.Attribute("Attr5", 5)]), None,
'int32'))),
ast.Enum(
'MyEnum',
- ast.AttributeList(ast.Attribute("Attr5", 5)),
+ ast.AttributeList(ast.Attribute("Attr6", 6)),
ast.EnumValueList(
ast.EnumValue(
- 'VALUE', ast.AttributeList([ast.Attribute("Attr6", 6)]),
+ 'VALUE', ast.AttributeList([ast.Attribute("Attr7", 7)]),
None))),
ast.Interface(
'MyInterface',
- ast.AttributeList(ast.Attribute("Attr7", 7)),
+ ast.AttributeList(ast.Attribute("Attr8", 8)),
ast.InterfaceBody(
ast.Method(
'MyMethod',
- ast.AttributeList(ast.Attribute("Attr8", 8)),
+ ast.AttributeList(ast.Attribute("Attr9", 9)),
None,
ast.ParameterList(
ast.Parameter(
- 'a', ast.AttributeList([ast.Attribute("Attr9", 9)]),
+ 'a',
+ ast.AttributeList([ast.Attribute("Attr10", 10)]),
None, 'int32')),
ast.ParameterList(
ast.Parameter(
'b',
- ast.AttributeList([ast.Attribute("Attr10", 10)]),
- None, 'bool')))))])
+ ast.AttributeList([ast.Attribute("Attr11", 11)]),
+ None, 'bool'))))),
+ ast.Const(
+ 'kMyConst',
+ ast.AttributeList(ast.Attribute("Attr12", 12)),
+ 'double', '1.23')])
self.assertEquals(parser.Parse(source4, "my_file.mojom"), expected4)
# TODO(vtl): Boolean attributes don't work yet. (In fact, we just |eval()|
@@ -1085,7 +1095,7 @@ class ParserTest(unittest.TestCase):
source1 = "import \"somedir/my.mojom\";"
expected1 = ast.Mojom(
None,
- ast.ImportList(ast.Import("somedir/my.mojom")),
+ ast.ImportList(ast.Import(None, "somedir/my.mojom")),
[])
self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
@@ -1096,8 +1106,8 @@ class ParserTest(unittest.TestCase):
"""
expected2 = ast.Mojom(
None,
- ast.ImportList([ast.Import("somedir/my1.mojom"),
- ast.Import("somedir/my2.mojom")]),
+ ast.ImportList([ast.Import(None, "somedir/my1.mojom"),
+ ast.Import(None, "somedir/my2.mojom")]),
[])
self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
@@ -1109,8 +1119,8 @@ class ParserTest(unittest.TestCase):
"""
expected3 = ast.Mojom(
ast.Module(('IDENTIFIER', 'my_module'), None),
- ast.ImportList([ast.Import("somedir/my1.mojom"),
- ast.Import("somedir/my2.mojom")]),
+ ast.ImportList([ast.Import(None, "somedir/my1.mojom"),
+ ast.Import(None, "somedir/my2.mojom")]),
[])
self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)