Commit 21075b5d authored by qsr@chromium.org's avatar qsr@chromium.org

Generate java bindings for constants.

This CL is the first CL introducing java bindings. It only generates constants.

This is a reland of https://codereview.chromium.org/291903003 with a custom
DEPS file to fix bot issue.

TBR=viettrungluu@chromium.org,rmcilroy@chromium.org

Review URL: https://codereview.chromium.org/312643003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274431 0039d316-1c4b-4281-b951-d872f2087c98
parent c4c9c8cf
include_rules = [
# out should be allowed by default, but bots are failing on this.
"+out",
]
// Copyright 2014 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.
package org.chromium.mojo.bindings;
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;
import org.chromium.mojo.bindings.test.sample.SampleServiceConstants;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* Testing generated classes and associated features.
*/
public class BindingsTest extends TestCase {
/**
* Testing constants are correctly generated.
*/
@SmallTest
public void testConstants() throws NoSuchFieldException, SecurityException {
assertEquals(3, SampleServiceConstants.THREE);
Field threeField = SampleServiceConstants.class.getField("THREE");
assertEquals(byte.class, threeField.getType());
assertEquals(Modifier.FINAL, threeField.getModifiers() & Modifier.FINAL);
assertEquals(Modifier.STATIC, threeField.getModifiers() & Modifier.STATIC);
}
}
{% from "java_macros.tmpl" import build_default %}
{% macro constant_def(constant) %}
public static final {{constant.kind|java_type}} {{constant|name}} = {{build_default(module, constant.kind, constant.value)|indent(4)}};
{% endmacro %}
{% from "constant_definition.tmpl" import constant_def %}
{% include "header.java.tmpl" %}
public final class {{main_entity}} {
{% for constant in constants %}
{{constant_def(constant)|indent(4)}}
{% endfor %}
private {{main_entity}}() {}
}
// Copyright 2014 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.
// This file is autogenerated by:
// mojo/public/tools/bindings/mojom_bindings_generator.py
// For:
// {{module.path}}
//
package {{package}};
{% macro build_default(module, kind, value) %}
({{kind|java_type}}) {{value|expression_to_text(module)}}
{% endmacro %}
# Copyright 2014 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 java source files from a mojom.Module."""
import argparse
import os
import re
import mojom.generate.generator as generator
import mojom.generate.module as mojom
from mojom.generate.template_expander import UseJinja
GENERATOR_PREFIX = 'java'
_spec_to_java_type = {
'b': 'boolean',
'd': 'double',
'f': 'float',
'h:d:c': 'org.chromium.mojo.system.DataPipe.ConsumerHandle',
'h:d:p': 'org.chromium.mojo.system.DataPipe.ProducerHandle',
'h:m': 'org.chromium.mojo.system.MessagePipeHandle',
'h': 'org.chromium.mojo.system.UntypedHandle',
'h:s': 'org.chromium.mojo.system.SharedBufferHandle',
'i16': 'short',
'i32': 'int',
'i64': 'long',
'i8': 'byte',
's': 'String',
'u16': 'short',
'u32': 'int',
'u64': 'long',
'u8': 'byte',
}
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)
return [x.lower() for x in name.split('_')]
def CapitalizeFirst(string):
return string[0].upper() + string[1:]
def UpperCamelCase(name):
return ''.join([CapitalizeFirst(x) for x in NameToComponent(name)])
def CamelCase(name):
uccc = UpperCamelCase(name)
return uccc[0].lower() + uccc[1:]
def ConstantStyle(name):
components = NameToComponent(name)
if components[0] == 'k':
components = components[1:]
return '_'.join([x.upper() for x in components])
def GetNameForElement(element):
if (isinstance(element, mojom.Enum) or
isinstance(element, mojom.Interface) or
isinstance(element, mojom.Struct)):
return UpperCamelCase(element.name)
if (isinstance(element, mojom.Method) or
isinstance(element, mojom.Parameter) or
isinstance(element, mojom.Field)):
return CamelCase(element.name)
if isinstance(element, mojom.EnumValue):
return (UpperCamelCase(element.enum_name) + '.' +
ConstantStyle(element.name))
if (isinstance(element, mojom.NamedValue) or
isinstance(element, mojom.Constant)):
return ConstantStyle(element.name)
raise Exception("Unexpected element: " % element)
def GetPackage(module):
if 'JavaPackage' in module.attributes:
package = module.attributes['JavaPackage']
if isinstance(package, basestring):
return package
assert package[0] == 'EXPRESSION'
assert len(package[1]) == 1
return package[1][0][1:-1].encode('string_escape')
# Default package.
return "org.chromium.mojom." + module.namespace
def GetNameForKind(kind):
def _GetNameHierachy(kind):
hierachy = []
if kind.parent_kind:
hierachy = _GetNameHierachy(kind.parent_kind)
hierachy.append(kind.name)
return hierachy
elements = [GetPackage(kind.module)]
elements += _GetNameHierachy(kind)
return '.'.join(elements)
def GetJavaType(kind):
if isinstance(kind, (mojom.Struct, mojom.Interface)):
return GetNameForKind(kind)
if isinstance(kind, mojom.Array):
return "%s[]" % GetJavaType(kind.kind)
if isinstance(kind, mojom.Enum):
return "int"
return _spec_to_java_type[kind.spec]
def TranslateConstants(token, module):
def _TranslateNamedValue(named_value):
entity_name = GetNameForElement(named_value)
if named_value.parent_kind:
return GetJavaType(named_value.parent_kind) + '.' + entity_name
# Handle the case where named_value is a module level constant:
if not isinstance(named_value, mojom.EnumValue):
entity_name = (GetConstantsMainEntityName(named_value.module) + '.' +
entity_name)
return GetPackage(named_value.module) + '.' + entity_name
if isinstance(token, mojom.NamedValue):
return _TranslateNamedValue(token)
# Add Long suffix to all number literals.
if re.match('^[0-9]+$', token):
return token + 'L'
return token
def ExpressionToText(value, module):
if value[0] != "EXPRESSION":
raise Exception("Expected EXPRESSION, got" + value)
return "".join(generator.ExpressionMapper(value,
lambda token: TranslateConstants(token, module)))
def GetConstantsMainEntityName(module):
# This constructs the name of the embedding classes for module level constants
# by extracting the mojom's filename and prepending it to Constants.
return (UpperCamelCase(module.path.split('/')[-1].rsplit('.', 1)[0]) +
'Constants')
class Generator(generator.Generator):
java_filters = {
"expression_to_text": ExpressionToText,
"java_type": GetJavaType,
"name": GetNameForElement,
"verify_token_type": generator.VerifyTokenType,
}
def GetJinjaExports(self):
return {
"module": self.module,
"package": GetPackage(self.module),
}
@UseJinja("java_templates/constants.java.tmpl", filters=java_filters,
lstrip_blocks=True, trim_blocks=True)
def GenerateConstantsSource(self, module):
exports = self.GetJinjaExports()
exports.update({"main_entity": GetConstantsMainEntityName(module),
"constants": module.constants})
return exports
def GenerateFiles(self, unparsed_args):
parser = argparse.ArgumentParser()
parser.add_argument("--java_output_directory", dest="java_output_directory")
args = parser.parse_args(unparsed_args)
if self.output_dir and args.java_output_directory:
self.output_dir = os.path.join(args.java_output_directory,
GetPackage(self.module).replace('.', '/'))
if not os.path.exists(self.output_dir):
try:
os.makedirs(self.output_dir)
except:
# Ignore errors on directory creation.
pass
if self.module.constants:
self.Write(self.GenerateConstantsSource(self.module),
"%s.java" % GetConstantsMainEntityName(self.module))
...@@ -5,13 +5,14 @@ ...@@ -5,13 +5,14 @@
{ {
'rules': [ 'rules': [
{ {
'rule_name': 'Generate C++ source files from mojom files', 'rule_name': 'Generate C++, JS and Java source files from mojom files',
'extension': 'mojom', 'extension': 'mojom',
'variables': { 'variables': {
'mojom_base_output_dir': 'mojom_base_output_dir':
'<!(python <(DEPTH)/build/inverse_depth.py <(DEPTH))', '<!(python <(DEPTH)/build/inverse_depth.py <(DEPTH))',
'mojom_bindings_generator': 'mojom_bindings_generator':
'<(DEPTH)/mojo/public/tools/bindings/mojom_bindings_generator.py', '<(DEPTH)/mojo/public/tools/bindings/mojom_bindings_generator.py',
'java_out_dir': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src',
}, },
'inputs': [ 'inputs': [
'<(mojom_bindings_generator)', '<(mojom_bindings_generator)',
...@@ -34,11 +35,16 @@ ...@@ -34,11 +35,16 @@
'<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/java_macros.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl',
'<(DEPTH)/mojo/public/tools/bindings/generators/mojom_cpp_generator.py', '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_cpp_generator.py',
'<(DEPTH)/mojo/public/tools/bindings/generators/mojom_java_generator.py',
'<(DEPTH)/mojo/public/tools/bindings/generators/mojom_js_generator.py', '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_js_generator.py',
'<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/__init__.py', '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/__init__.py',
'<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/error.py', '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/error.py',
...@@ -66,6 +72,7 @@ ...@@ -66,6 +72,7 @@
'--use_chromium_bundled_pylibs', '--use_chromium_bundled_pylibs',
'-d', '<(DEPTH)', '-d', '<(DEPTH)',
'-o', '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)', '-o', '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)',
'--java_output_directory=<(java_out_dir)',
], ],
'message': 'Generating Mojo bindings from <(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom', 'message': 'Generating Mojo bindings from <(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom',
'process_outputs_as_sources': 1, 'process_outputs_as_sources': 1,
...@@ -80,6 +87,11 @@ ...@@ -80,6 +87,11 @@
'<(DEPTH)', '<(DEPTH)',
'<(SHARED_INTERMEDIATE_DIR)', '<(SHARED_INTERMEDIATE_DIR)',
], ],
'variables': {
'generated_src_dirs': [
'<(PRODUCT_DIR)/java_mojo/<(_target_name)/src',
],
},
}, },
'hard_dependency': 1, 'hard_dependency': 1,
} }
...@@ -53,6 +53,9 @@ def LoadGenerators(generators_string): ...@@ -53,6 +53,9 @@ def LoadGenerators(generators_string):
elif generator_name.lower() == "javascript": elif generator_name.lower() == "javascript":
generator_name = os.path.join(script_dir, "generators", generator_name = os.path.join(script_dir, "generators",
"mojom_js_generator.py") "mojom_js_generator.py")
elif generator_name.lower() == "java":
generator_name = os.path.join(script_dir, "generators",
"mojom_java_generator.py")
# Specified generator python module: # Specified generator python module:
elif generator_name.endswith(".py"): elif generator_name.endswith(".py"):
pass pass
...@@ -153,7 +156,7 @@ def main(): ...@@ -153,7 +156,7 @@ def main():
parser.add_argument("-o", "--output_dir", dest="output_dir", default=".", parser.add_argument("-o", "--output_dir", dest="output_dir", default=".",
help="output directory for generated files") help="output directory for generated files")
parser.add_argument("-g", "--generators", dest="generators_string", parser.add_argument("-g", "--generators", dest="generators_string",
metavar="GENERATORS", default="c++,javascript", metavar="GENERATORS", default="c++,javascript,java",
help="comma-separated list of generators") help="comma-separated list of generators")
parser.add_argument("--debug_print_intermediate", action="store_true", parser.add_argument("--debug_print_intermediate", action="store_true",
help="print the intermediate representation") help="print the intermediate representation")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment