Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(583)

Unified Diff: mojo/public/tools/bindings/generators/mojom_java_generator.py

Issue 291903003: Generate java bindings for constants. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add private constructor to constants class. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: mojo/public/tools/bindings/generators/mojom_java_generator.py
diff --git a/mojo/public/tools/bindings/generators/mojom_java_generator.py b/mojo/public/tools/bindings/generators/mojom_java_generator.py
new file mode 100644
index 0000000000000000000000000000000000000000..b514ecb553b7a7f43d798854dd03e516db22af2b
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/mojom_java_generator.py
@@ -0,0 +1,272 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generates java source files from a mojom.Module."""
+
+import argparse
+import os
+
+import mojom.generate.generator as generator
+import mojom.generate.module as mojom
+import mojom.generate.pack as pack
+from mojom.generate.template_expander import UseJinja
+
+
+GENERATOR_PREFIX = 'java'
rmcilroy 2014/05/25 22:55:10 Is this needed - it doesn't seem to be referenced.
qsr 2014/05/26 08:41:20 It is used by mojo/public/tools/bindings/mojom_bin
+
+_HEADER_SIZE = 8
+
+_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",
+}
+
+_spec_to_decode_method = {
+ 'b': "readBoolean",
+ 'd': "readDouble",
+ 'f': "readFloat",
+ 'h:d:c': "readConsumerHandle",
+ 'h:d:p': "readProducerHandle",
+ 'h:m': "readMessagePipeHandle",
+ 'h': "readUntypedHandle",
+ 'h:s': "readSharedBufferHandle",
+ 'i16': "readShort",
+ 'i32': "readInt",
+ 'i64': "readLong",
+ 'i8': "readByte",
+ 's': "readString",
+ 'u16': "readShort",
+ 'u32': "readInt",
+ 'u64': "readLong",
+ 'u8': "readByte",
+}
+
+
+def DecodeMethod(kind):
+ if isinstance(kind, mojom.Array):
+ return DecodeMethod(kind.kind) + 's'
+ if isinstance(kind, mojom.Enum):
+ return DecodeMethod(mojom.INT32)
+ if isinstance(kind, mojom.Interface):
+ return "readServiceInterface"
+ return _spec_to_decode_method[kind.spec]
+
+def NamespaceToArray(namespace):
rmcilroy 2014/05/25 22:55:10 I think this should be called PackageToArray(packa
qsr 2014/05/26 08:41:20 Removed.
+ return namespace.split('.')
+
+def GetNameFromString(string):
rmcilroy 2014/05/25 22:55:10 I would call this "UpperCamelCase" and move it wit
qsr 2014/05/26 08:41:20 Refactored naming function. This method doesn't ex
+ return CapitalizeFirst(CamelCase(string))
+
+def GetName(kind):
rmcilroy 2014/05/25 22:55:10 I would get rid of this method - the name is confu
qsr 2014/05/26 08:41:20 Done.
+ return GetNameFromString(kind.name)
+
+def GetPackage(module):
+ if 'JavaPackage' in module.attributes:
+ package = module.attributes['JavaPackage']
+ if isinstance(package, basestring):
+ return package
+ assert package[0] == 'EXPRESSION'
rmcilroy 2014/05/25 22:55:10 It's probably clearer to include "else" branches e
qsr 2014/05/26 08:41:20 That's not the style other python file use. Revers
+ assert len(package[1]) == 1
+ return package[1][0][1:-1].encode('string_escape')
+ return "org.chromium.mojom." + module.namespace
+
+def GetSuperClass(method):
+ if method:
+ if method.response_parameters:
+ return "org.chromium.mojo.bindings.MessageWithRequestId"
+ return "org.chromium.mojo.bindings.Message"
+ return "org.chromium.mojo.bindings.Struct"
rmcilroy 2014/05/25 22:55:10 I think this would be clearer as: if not method:
qsr 2014/05/26 08:41:20 Method removed until further CL.
+
+def GetFlags(method, is_parameter):
rmcilroy 2014/05/25 22:55:10 Could you remove this until it's used in a later C
qsr 2014/05/26 08:41:20 Done.
+ if method.response_parameters:
+ if is_parameter:
+ return "MESSAGE_EXPECTS_RESPONSE_FLAG"
+ return "MESSAGE_IS_RESPONSE_FLAG"
+ return "0"
+
+def NewArray(kind, size):
rmcilroy 2014/05/25 22:55:10 nit - move below GetMethodName
qsr 2014/05/26 08:41:20 Removed.
+ if isinstance(kind.kind, mojom.Array):
+ return NewArray(kind.kind, size) + '[]'
+ return 'new %s[%s]' % (GetJavaType(kind.kind), size)
+
+def GetNameHierachy(kind):
rmcilroy 2014/05/25 22:55:10 Could you make GetNameHierarchy an inner function
qsr 2014/05/26 08:41:20 Done.
+ hierachy = []
+ if kind.parent_kind:
+ hierachy = GetNameHierachy(kind.parent_kind)
+ hierachy.append(kind.name)
+ return hierachy
+
+def GetNameForKind(kind):
+ elements = [GetPackage(kind.module)]
+ elements += GetNameHierachy(kind)
+ return '.'.join(elements)
+
+def GetJavaGetterPrefix(kind):
+ if kind == mojom.BOOL:
+ return "is"
+ return "get"
+
+def GetJavaType(kind):
+ if isinstance(kind, mojom.Struct):
+ return GetNameForKind(kind)
+ if isinstance(kind, mojom.Array):
+ return "%s[]" % GetJavaType(kind.kind)
+ if isinstance(kind, mojom.Interface):
+ return "org.chromium.mojo.bindings.ServiceHandle<%s>" % GetNameForKind(kind)
+ if isinstance(kind, mojom.Enum):
+ return "int"
+ return _spec_to_java_type[kind.spec]
+
+def TranslateConstants(token, module):
+ if isinstance(token, (mojom.NamedValue, mojom.EnumValue)):
+ if isinstance(token, mojom.EnumValue):
+ entity_value = token.enum_name + '.' + token.name
+ else:
+ entity_value = ConstantName(token)
+ if not token.parent_kind:
+ entity_value = (GetConstantsMainEntityName(token.module) +
+ '.' + entity_value)
+ if token.parent_kind:
+ return GetJavaType(token.parent_kind) + '.' + entity_value
+ return GetPackage(token.module) + '.' + entity_value
rmcilroy 2014/05/25 22:55:10 Could you please reduce this method to the bare mi
qsr 2014/05/26 08:41:20 This is mostly the bare minimum. A constant can re
+ return token
+
+def ExpressionToText(value, module):
rmcilroy 2014/05/25 22:55:10 This looks the same as the method in the CPP bindi
qsr 2014/05/26 08:41:20 We can do this in a further CL if you do not mind.
rmcilroy 2014/05/26 11:13:48 Doing this in a separate cl is fine. BTW, I was on
+ if value[0] != "EXPRESSION":
+ raise Exception("Expected EXPRESSION, got" + value)
+ return "".join(generator.ExpressionMapper(value,
+ lambda token: TranslateConstants(token, module)))
+
+def CapitalizeFirst(string):
+ return string[0].upper() + string[1:]
+
+def CamelCase(string):
+ elements = string.split('_')
+ return elements[0] + ''.join([x.capitalize() for x in elements[1:]])
+
+def UpperCaseConstant(name):
+ def _IsCut(i):
+ if i == 0 or i == len(name):
+ return True
+ if name[i].islower():
+ return False
+ if name[i-1].isupper() and (i == len(name) -1 or name[i+1].isupper()):
+ return False
+ return True
+ pos = [i for i in xrange(len(name) + 1) if _IsCut(i)]
+ parts = [name[pos[j]:pos[j+1]] for j in xrange(len(pos)-1)]
+ return '_'.join([x.upper() for x in parts])
rmcilroy 2014/05/25 22:55:10 I think you could do this more easily with a regex
qsr 2014/05/26 08:41:20 This has been completely refactored.
+
+def DefaultValueConstant(field):
+ return 'DEFAULT_' + UpperCaseConstant(GetName(field))
rmcilroy 2014/05/25 22:55:10 Please remove this until the CL where it is used.
qsr 2014/05/26 08:41:20 Done.
+
+def FieldName(field):
+ return 'm' + GetName(field)
+
+def ConstantName(constant):
+ main_name = constant.name
+ if main_name[0] == 'k':
+ main_name = main_name[1:]
+ return UpperCaseConstant(main_name)
+
+def IsPointerArrayKind(kind):
rmcilroy 2014/05/25 22:55:10 Please remove IsPointerArrayKind, GetResponseStruc
qsr 2014/05/26 08:41:20 Done.
+ if not isinstance(kind, mojom.Array):
+ return False
+ sub_kind = kind.kind
+ return generator.IsObjectKind(sub_kind)
+
+def GetResponseStructFromMethod(method):
+ return generator.GetDataHeader(
+ False, generator.GetResponseStructFromMethod(method))
+
+def GetStructFromMethod(method):
+ return generator.GetDataHeader(
+ False, generator.GetStructFromMethod(method))
+
+def GetMethodName(method):
+ return (UpperCaseConstant(method.interface.name) + "_" +
+ UpperCaseConstant(method.name) + "_NAME")
+
+def GetConstantsMainEntityFullyQualifiedName(module):
rmcilroy 2014/05/25 22:55:10 This doesn't seem to be used - can it be removed (
qsr 2014/05/26 08:41:20 This is now used.
+ package = GetPackage(module)
+ return GetPackage(module) + '.' + GetConstantsMainEntityName(module)
+
+def GetConstantsMainEntityName(module):
+ return (GetNameFromString(module.path.split('/')[-1].rsplit('.', 1)[0]) +
rmcilroy 2014/05/25 22:55:10 Please add a comment describing that this is build
qsr 2014/05/26 08:41:20 Added the comment. I'd rather do the annotation in
+ 'Constants')
+
+class Generator(generator.Generator):
+
+ java_filters = {
+ "camelcase": CamelCase,
+ "capitalize_first": CapitalizeFirst,
+ "default_value_constant": DefaultValueConstant,
+ "decode_method": DecodeMethod,
+ "expression_to_text": ExpressionToText,
+ "field_name": FieldName,
+ "flags": GetFlags,
+ "is_bool": lambda kind: kind == mojom.BOOL,
+ "is_array_kind": lambda kind: isinstance(kind, mojom.Array),
+ "is_object_kind": generator.IsObjectKind,
+ "is_pointer_array_kind": IsPointerArrayKind,
+ "is_string_kind": generator.IsStringKind,
+ "is_struct_kind": lambda kind: isinstance(kind, mojom.Struct),
+ "java_getter_prefix": GetJavaGetterPrefix,
+ "java_type": GetJavaType,
+ "method_name": GetMethodName,
+ "new_array": NewArray,
+ "response_struct_from_method": GetResponseStructFromMethod,
+ "struct_from_method": GetStructFromMethod,
+ "struct_size": lambda ps: ps.GetTotalSize() + _HEADER_SIZE,
+ "super_class": GetSuperClass,
+ "constant_name": ConstantName,
+ "verify_token_type": generator.VerifyTokenType,
+ }
+
+ def GetJinjaExports(self):
+ return {
+ "interfaces": self.module.interfaces,
+ "kinds": self.module.kinds,
+ "method_structs": self.GetStructsFromMethods(),
rmcilroy 2014/05/25 22:55:10 I can't see any uses of "method_structs" either he
qsr 2014/05/26 08:41:20 Done.
+ "module": self.module,
+ "namespace": self.module.namespace,
+ "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):
+ os.makedirs(self.output_dir)
+
+ if self.module.constants:
+ self.Write(self.GenerateConstantsSource(self.module),
+ "%s.java" % GetConstantsMainEntityName(self.module))

Powered by Google App Engine
This is Rietveld 408576698