diff options
Diffstat (limited to 'mojo/public/tools/bindings/generators/mojom_java_generator.py')
-rw-r--r-- | mojo/public/tools/bindings/generators/mojom_java_generator.py | 550 |
1 files changed, 0 insertions, 550 deletions
diff --git a/mojo/public/tools/bindings/generators/mojom_java_generator.py b/mojo/public/tools/bindings/generators/mojom_java_generator.py deleted file mode 100644 index c7657ff..0000000 --- a/mojo/public/tools/bindings/generators/mojom_java_generator.py +++ /dev/null @@ -1,550 +0,0 @@ -# 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 ast -import contextlib -import os -import re -import shutil -import sys -import tempfile - -from jinja2 import contextfilter - -import mojom.fileutil as fileutil -import mojom.generate.generator as generator -import mojom.generate.module as mojom -from mojom.generate.template_expander import UseJinja - -sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, - os.pardir, os.pardir, os.pardir, os.pardir, - 'build', 'android', 'gyp')) -from util import build_utils - - -GENERATOR_PREFIX = 'java' - -_spec_to_java_type = { - mojom.BOOL.spec: 'boolean', - mojom.DCPIPE.spec: 'org.chromium.mojo.system.DataPipe.ConsumerHandle', - mojom.DOUBLE.spec: 'double', - mojom.DPPIPE.spec: 'org.chromium.mojo.system.DataPipe.ProducerHandle', - mojom.FLOAT.spec: 'float', - mojom.HANDLE.spec: 'org.chromium.mojo.system.UntypedHandle', - mojom.INT16.spec: 'short', - mojom.INT32.spec: 'int', - mojom.INT64.spec: 'long', - mojom.INT8.spec: 'byte', - mojom.MSGPIPE.spec: 'org.chromium.mojo.system.MessagePipeHandle', - mojom.NULLABLE_DCPIPE.spec: - 'org.chromium.mojo.system.DataPipe.ConsumerHandle', - mojom.NULLABLE_DPPIPE.spec: - 'org.chromium.mojo.system.DataPipe.ProducerHandle', - mojom.NULLABLE_HANDLE.spec: 'org.chromium.mojo.system.UntypedHandle', - mojom.NULLABLE_MSGPIPE.spec: 'org.chromium.mojo.system.MessagePipeHandle', - mojom.NULLABLE_SHAREDBUFFER.spec: - 'org.chromium.mojo.system.SharedBufferHandle', - mojom.NULLABLE_STRING.spec: 'String', - mojom.SHAREDBUFFER.spec: 'org.chromium.mojo.system.SharedBufferHandle', - mojom.STRING.spec: 'String', - mojom.UINT16.spec: 'short', - mojom.UINT32.spec: 'int', - mojom.UINT64.spec: 'long', - mojom.UINT8.spec: 'byte', -} - -_spec_to_decode_method = { - mojom.BOOL.spec: 'readBoolean', - mojom.DCPIPE.spec: 'readConsumerHandle', - mojom.DOUBLE.spec: 'readDouble', - mojom.DPPIPE.spec: 'readProducerHandle', - mojom.FLOAT.spec: 'readFloat', - mojom.HANDLE.spec: 'readUntypedHandle', - mojom.INT16.spec: 'readShort', - mojom.INT32.spec: 'readInt', - mojom.INT64.spec: 'readLong', - mojom.INT8.spec: 'readByte', - mojom.MSGPIPE.spec: 'readMessagePipeHandle', - mojom.NULLABLE_DCPIPE.spec: 'readConsumerHandle', - mojom.NULLABLE_DPPIPE.spec: 'readProducerHandle', - mojom.NULLABLE_HANDLE.spec: 'readUntypedHandle', - mojom.NULLABLE_MSGPIPE.spec: 'readMessagePipeHandle', - mojom.NULLABLE_SHAREDBUFFER.spec: 'readSharedBufferHandle', - mojom.NULLABLE_STRING.spec: 'readString', - mojom.SHAREDBUFFER.spec: 'readSharedBufferHandle', - mojom.STRING.spec: 'readString', - mojom.UINT16.spec: 'readShort', - mojom.UINT32.spec: 'readInt', - mojom.UINT64.spec: 'readLong', - mojom.UINT8.spec: 'readByte', -} - -_java_primitive_to_boxed_type = { - 'boolean': 'Boolean', - 'byte': 'Byte', - 'double': 'Double', - 'float': 'Float', - 'int': 'Integer', - 'long': 'Long', - 'short': 'Short', -} - - -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 UpperCamelCase(name): - return ''.join([x.capitalize() 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' and len(components) > 1: - components = components[1:] - # variable cannot starts with a digit. - if components[0][0].isdigit(): - components[0] = '_' + components[0] - return '_'.join([x.upper() for x in components]) - -def GetNameForElement(element): - if (mojom.IsEnumKind(element) or mojom.IsInterfaceKind(element) or - mojom.IsStructKind(element) or mojom.IsUnionKind(element)): - return UpperCamelCase(element.name) - if mojom.IsInterfaceRequestKind(element) or mojom.IsAssociatedKind(element): - return GetNameForElement(element.kind) - if isinstance(element, (mojom.Method, - mojom.Parameter, - mojom.Field)): - return CamelCase(element.name) - if isinstance(element, mojom.EnumValue): - return (GetNameForElement(element.enum) + '.' + - ConstantStyle(element.name)) - if isinstance(element, (mojom.NamedValue, - mojom.Constant, - mojom.EnumField)): - return ConstantStyle(element.name) - raise Exception('Unexpected element: %s' % element) - -def GetInterfaceResponseName(method): - return UpperCamelCase(method.name + 'Response') - -def ParseStringAttribute(attribute): - assert isinstance(attribute, basestring) - return attribute - -def GetJavaTrueFalse(value): - return 'true' if value else 'false' - -def GetArrayNullabilityFlags(kind): - """Returns nullability flags for an array type, see Decoder.java. - - As we have dedicated decoding functions for arrays, we have to pass - nullability information about both the array itself, as well as the array - element type there. - """ - assert mojom.IsArrayKind(kind) - ARRAY_NULLABLE = \ - 'org.chromium.mojo.bindings.BindingsHelper.ARRAY_NULLABLE' - ELEMENT_NULLABLE = \ - 'org.chromium.mojo.bindings.BindingsHelper.ELEMENT_NULLABLE' - NOTHING_NULLABLE = \ - 'org.chromium.mojo.bindings.BindingsHelper.NOTHING_NULLABLE' - - flags_to_set = [] - if mojom.IsNullableKind(kind): - flags_to_set.append(ARRAY_NULLABLE) - if mojom.IsNullableKind(kind.kind): - flags_to_set.append(ELEMENT_NULLABLE) - - if not flags_to_set: - flags_to_set = [NOTHING_NULLABLE] - return ' | '.join(flags_to_set) - - -def AppendEncodeDecodeParams(initial_params, context, kind, bit): - """ Appends standard parameters shared between encode and decode calls. """ - params = list(initial_params) - if (kind == mojom.BOOL): - params.append(str(bit)) - if mojom.IsReferenceKind(kind): - if mojom.IsArrayKind(kind): - params.append(GetArrayNullabilityFlags(kind)) - else: - params.append(GetJavaTrueFalse(mojom.IsNullableKind(kind))) - if mojom.IsArrayKind(kind): - params.append(GetArrayExpectedLength(kind)) - if mojom.IsInterfaceKind(kind): - params.append('%s.MANAGER' % GetJavaType(context, kind)) - if mojom.IsArrayKind(kind) and mojom.IsInterfaceKind(kind.kind): - params.append('%s.MANAGER' % GetJavaType(context, kind.kind)) - return params - - -@contextfilter -def DecodeMethod(context, kind, offset, bit): - def _DecodeMethodName(kind): - if mojom.IsArrayKind(kind): - return _DecodeMethodName(kind.kind) + 's' - if mojom.IsEnumKind(kind): - return _DecodeMethodName(mojom.INT32) - if mojom.IsInterfaceRequestKind(kind): - return 'readInterfaceRequest' - if mojom.IsInterfaceKind(kind): - return 'readServiceInterface' - if mojom.IsAssociatedInterfaceRequestKind(kind): - return 'readAssociatedInterfaceRequestNotSupported' - if mojom.IsAssociatedInterfaceKind(kind): - return 'readAssociatedServiceInterfaceNotSupported' - return _spec_to_decode_method[kind.spec] - methodName = _DecodeMethodName(kind) - params = AppendEncodeDecodeParams([ str(offset) ], context, kind, bit) - return '%s(%s)' % (methodName, ', '.join(params)) - -@contextfilter -def EncodeMethod(context, kind, variable, offset, bit): - params = AppendEncodeDecodeParams( - [ variable, str(offset) ], context, kind, bit) - return 'encode(%s)' % ', '.join(params) - -def GetPackage(module): - if module.attributes and 'JavaPackage' in module.attributes: - return ParseStringAttribute(module.attributes['JavaPackage']) - # Default package. - if module.namespace: - return 'org.chromium.' + module.namespace - return 'org.chromium' - -def GetNameForKind(context, kind): - def _GetNameHierachy(kind): - hierachy = [] - if kind.parent_kind: - hierachy = _GetNameHierachy(kind.parent_kind) - hierachy.append(GetNameForElement(kind)) - return hierachy - - module = context.resolve('module') - elements = [] - if GetPackage(module) != GetPackage(kind.module): - elements += [GetPackage(kind.module)] - elements += _GetNameHierachy(kind) - return '.'.join(elements) - -@contextfilter -def GetJavaClassForEnum(context, kind): - return GetNameForKind(context, kind) - -def GetBoxedJavaType(context, kind, with_generics=True): - unboxed_type = GetJavaType(context, kind, False, with_generics) - if unboxed_type in _java_primitive_to_boxed_type: - return _java_primitive_to_boxed_type[unboxed_type] - return unboxed_type - -@contextfilter -def GetJavaType(context, kind, boxed=False, with_generics=True): - if boxed: - return GetBoxedJavaType(context, kind) - if (mojom.IsStructKind(kind) or - mojom.IsInterfaceKind(kind) or - mojom.IsUnionKind(kind)): - return GetNameForKind(context, kind) - if mojom.IsInterfaceRequestKind(kind): - return ('org.chromium.mojo.bindings.InterfaceRequest<%s>' % - GetNameForKind(context, kind.kind)) - if mojom.IsAssociatedInterfaceKind(kind): - return 'org.chromium.mojo.bindings.AssociatedInterfaceNotSupported' - if mojom.IsAssociatedInterfaceRequestKind(kind): - return 'org.chromium.mojo.bindings.AssociatedInterfaceRequestNotSupported' - if mojom.IsMapKind(kind): - if with_generics: - return 'java.util.Map<%s, %s>' % ( - GetBoxedJavaType(context, kind.key_kind), - GetBoxedJavaType(context, kind.value_kind)) - else: - return 'java.util.Map' - if mojom.IsArrayKind(kind): - return '%s[]' % GetJavaType(context, kind.kind, boxed, with_generics) - if mojom.IsEnumKind(kind): - return 'int' - return _spec_to_java_type[kind.spec] - -@contextfilter -def DefaultValue(context, field): - assert field.default - if isinstance(field.kind, mojom.Struct): - assert field.default == 'default' - return 'new %s()' % GetJavaType(context, field.kind) - return '(%s) %s' % ( - GetJavaType(context, field.kind), - ExpressionToText(context, field.default, kind_spec=field.kind.spec)) - -@contextfilter -def ConstantValue(context, constant): - return '(%s) %s' % ( - GetJavaType(context, constant.kind), - ExpressionToText(context, constant.value, kind_spec=constant.kind.spec)) - -@contextfilter -def NewArray(context, kind, size): - if mojom.IsArrayKind(kind.kind): - return NewArray(context, kind.kind, size) + '[]' - return 'new %s[%s]' % ( - GetJavaType(context, kind.kind, boxed=False, with_generics=False), size) - -@contextfilter -def ExpressionToText(context, token, kind_spec=''): - def _TranslateNamedValue(named_value): - entity_name = GetNameForElement(named_value) - if named_value.parent_kind: - return GetJavaType(context, 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) - if GetPackage(named_value.module) == GetPackage(context.resolve('module')): - return entity_name - return GetPackage(named_value.module) + '.' + entity_name - - if isinstance(token, mojom.NamedValue): - return _TranslateNamedValue(token) - if kind_spec.startswith('i') or kind_spec.startswith('u'): - # Add Long suffix to all integer literals. - number = ast.literal_eval(token.lstrip('+ ')) - if not isinstance(number, (int, long)): - raise ValueError('got unexpected type %r for int literal %r' % ( - type(number), token)) - # If the literal is too large to fit a signed long, convert it to the - # equivalent signed long. - if number >= 2 ** 63: - number -= 2 ** 64 - return '%dL' % number - if isinstance(token, mojom.BuiltinValue): - if token.value == 'double.INFINITY': - return 'java.lang.Double.POSITIVE_INFINITY' - if token.value == 'double.NEGATIVE_INFINITY': - return 'java.lang.Double.NEGATIVE_INFINITY' - if token.value == 'double.NAN': - return 'java.lang.Double.NaN' - if token.value == 'float.INFINITY': - return 'java.lang.Float.POSITIVE_INFINITY' - if token.value == 'float.NEGATIVE_INFINITY': - return 'java.lang.Float.NEGATIVE_INFINITY' - if token.value == 'float.NAN': - return 'java.lang.Float.NaN' - return token - -def GetArrayKind(kind, size = None): - if size is None: - return mojom.Array(kind) - else: - array = mojom.Array(kind, 0) - array.java_map_size = size - return array - -def GetArrayExpectedLength(kind): - if mojom.IsArrayKind(kind) and kind.length is not None: - return getattr(kind, 'java_map_size', str(kind.length)) - else: - return 'org.chromium.mojo.bindings.BindingsHelper.UNSPECIFIED_ARRAY_LENGTH' - -def IsPointerArrayKind(kind): - if not mojom.IsArrayKind(kind): - return False - sub_kind = kind.kind - return mojom.IsObjectKind(sub_kind) and not mojom.IsUnionKind(sub_kind) - -def IsUnionArrayKind(kind): - if not mojom.IsArrayKind(kind): - return False - sub_kind = kind.kind - return mojom.IsUnionKind(sub_kind) - -def GetConstantsMainEntityName(module): - if module.attributes and 'JavaConstantsClassName' in module.attributes: - return ParseStringAttribute(module.attributes['JavaConstantsClassName']) - # 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') - -def GetMethodOrdinalName(method): - return ConstantStyle(method.name) + '_ORDINAL' - -def HasMethodWithResponse(interface): - for method in interface.methods: - if method.response_parameters is not None: - return True - return False - -def HasMethodWithoutResponse(interface): - for method in interface.methods: - if method.response_parameters is None: - return True - return False - -@contextlib.contextmanager -def TempDir(): - dirname = tempfile.mkdtemp() - try: - yield dirname - finally: - 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): - return { - 'package': GetPackage(self.module), - } - - @staticmethod - def GetTemplatePrefix(): - return "java_templates" - - @classmethod - def GetFilters(cls): - return cls.java_filters - - def GetJinjaExportsForInterface(self, interface): - exports = self.GetJinjaExports() - exports.update({'interface': interface}) - return exports - - @UseJinja('enum.java.tmpl') - def GenerateEnumSource(self, enum): - exports = self.GetJinjaExports() - exports.update({'enum': enum}) - return exports - - @UseJinja('struct.java.tmpl') - def GenerateStructSource(self, struct): - exports = self.GetJinjaExports() - exports.update({'struct': struct}) - return exports - - @UseJinja('union.java.tmpl') - 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) - - @UseJinja('interface_internal.java.tmpl') - def GenerateInterfaceInternalSource(self, interface): - return self.GetJinjaExportsForInterface(interface) - - @UseJinja('constants.java.tmpl') - def GenerateConstantsSource(self, module): - exports = self.GetJinjaExports() - exports.update({'main_entity': GetConstantsMainEntityName(module), - 'constants': module.constants}) - return exports - - 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), - '%s.java' % GetNameForElement(struct)) - - for union in self.module.unions: - self.Write(self.GenerateUnionSource(union), - '%s.java' % GetNameForElement(union)) - - for enum in self.module.enums: - self.Write(self.GenerateEnumSource(enum), - '%s.java' % GetNameForElement(enum)) - - for interface in self.GetInterfaces(): - self.Write(self.GenerateInterfaceSource(interface), - '%s.java' % GetNameForElement(interface)) - self.Write(self.GenerateInterfaceInternalSource(interface), - '%s_Internal.java' % GetNameForElement(interface)) - - if self.module.constants: - self.Write(self.GenerateConstantsSource(self.module), - '%s.java' % GetConstantsMainEntityName(self.module)) - - def GenerateFiles(self, unparsed_args): - # TODO(rockot): Support variant output for Java. - if self.variant: - raise Exception("Variants not supported in Java bindings.") - - parser = argparse.ArgumentParser() - parser.add_argument('--java_output_directory', dest='java_output_directory') - args = parser.parse_args(unparsed_args) - package_path = GetPackage(self.module).replace('.', '/') - - # 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) - 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(); - 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(); - - def GetJinjaParameters(self): - return { - 'lstrip_blocks': True, - 'trim_blocks': True, - } - - def GetGlobals(self): - return { - 'namespace': self.module.namespace, - 'module': self.module, - } |