Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 """Generates java source files from a mojom.Module.""" | |
| 6 | |
| 7 import argparse | |
| 8 import os | |
| 9 | |
| 10 import mojom.generate.generator as generator | |
| 11 import mojom.generate.module as mojom | |
| 12 import mojom.generate.pack as pack | |
| 13 from mojom.generate.template_expander import UseJinja | |
| 14 | |
| 15 | |
| 16 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
| |
| 17 | |
| 18 _HEADER_SIZE = 8 | |
| 19 | |
| 20 _spec_to_java_type = { | |
| 21 'b': "boolean", | |
| 22 'd': "double", | |
| 23 'f': "float", | |
| 24 'h:d:c': "org.chromium.mojo.system.DataPipe.ConsumerHandle", | |
| 25 'h:d:p': "org.chromium.mojo.system.DataPipe.ProducerHandle", | |
| 26 'h:m': "org.chromium.mojo.system.MessagePipeHandle", | |
| 27 'h': "org.chromium.mojo.system.UntypedHandle", | |
| 28 'h:s': "org.chromium.mojo.system.SharedBufferHandle", | |
| 29 'i16': "short", | |
| 30 'i32': "int", | |
| 31 'i64': "long", | |
| 32 'i8': "byte", | |
| 33 's': "String", | |
| 34 'u16': "short", | |
| 35 'u32': "int", | |
| 36 'u64': "long", | |
| 37 'u8': "byte", | |
| 38 } | |
| 39 | |
| 40 _spec_to_decode_method = { | |
| 41 'b': "readBoolean", | |
| 42 'd': "readDouble", | |
| 43 'f': "readFloat", | |
| 44 'h:d:c': "readConsumerHandle", | |
| 45 'h:d:p': "readProducerHandle", | |
| 46 'h:m': "readMessagePipeHandle", | |
| 47 'h': "readUntypedHandle", | |
| 48 'h:s': "readSharedBufferHandle", | |
| 49 'i16': "readShort", | |
| 50 'i32': "readInt", | |
| 51 'i64': "readLong", | |
| 52 'i8': "readByte", | |
| 53 's': "readString", | |
| 54 'u16': "readShort", | |
| 55 'u32': "readInt", | |
| 56 'u64': "readLong", | |
| 57 'u8': "readByte", | |
| 58 } | |
| 59 | |
| 60 | |
| 61 def DecodeMethod(kind): | |
| 62 if isinstance(kind, mojom.Array): | |
| 63 return DecodeMethod(kind.kind) + 's' | |
| 64 if isinstance(kind, mojom.Enum): | |
| 65 return DecodeMethod(mojom.INT32) | |
| 66 if isinstance(kind, mojom.Interface): | |
| 67 return "readServiceInterface" | |
| 68 return _spec_to_decode_method[kind.spec] | |
| 69 | |
| 70 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.
| |
| 71 return namespace.split('.') | |
| 72 | |
| 73 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
| |
| 74 return CapitalizeFirst(CamelCase(string)) | |
| 75 | |
| 76 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.
| |
| 77 return GetNameFromString(kind.name) | |
| 78 | |
| 79 def GetPackage(module): | |
| 80 if 'JavaPackage' in module.attributes: | |
| 81 package = module.attributes['JavaPackage'] | |
| 82 if isinstance(package, basestring): | |
| 83 return package | |
| 84 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
| |
| 85 assert len(package[1]) == 1 | |
| 86 return package[1][0][1:-1].encode('string_escape') | |
| 87 return "org.chromium.mojom." + module.namespace | |
| 88 | |
| 89 def GetSuperClass(method): | |
| 90 if method: | |
| 91 if method.response_parameters: | |
| 92 return "org.chromium.mojo.bindings.MessageWithRequestId" | |
| 93 return "org.chromium.mojo.bindings.Message" | |
| 94 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.
| |
| 95 | |
| 96 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.
| |
| 97 if method.response_parameters: | |
| 98 if is_parameter: | |
| 99 return "MESSAGE_EXPECTS_RESPONSE_FLAG" | |
| 100 return "MESSAGE_IS_RESPONSE_FLAG" | |
| 101 return "0" | |
| 102 | |
| 103 def NewArray(kind, size): | |
|
rmcilroy
2014/05/25 22:55:10
nit - move below GetMethodName
qsr
2014/05/26 08:41:20
Removed.
| |
| 104 if isinstance(kind.kind, mojom.Array): | |
| 105 return NewArray(kind.kind, size) + '[]' | |
| 106 return 'new %s[%s]' % (GetJavaType(kind.kind), size) | |
| 107 | |
| 108 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.
| |
| 109 hierachy = [] | |
| 110 if kind.parent_kind: | |
| 111 hierachy = GetNameHierachy(kind.parent_kind) | |
| 112 hierachy.append(kind.name) | |
| 113 return hierachy | |
| 114 | |
| 115 def GetNameForKind(kind): | |
| 116 elements = [GetPackage(kind.module)] | |
| 117 elements += GetNameHierachy(kind) | |
| 118 return '.'.join(elements) | |
| 119 | |
| 120 def GetJavaGetterPrefix(kind): | |
| 121 if kind == mojom.BOOL: | |
| 122 return "is" | |
| 123 return "get" | |
| 124 | |
| 125 def GetJavaType(kind): | |
| 126 if isinstance(kind, mojom.Struct): | |
| 127 return GetNameForKind(kind) | |
| 128 if isinstance(kind, mojom.Array): | |
| 129 return "%s[]" % GetJavaType(kind.kind) | |
| 130 if isinstance(kind, mojom.Interface): | |
| 131 return "org.chromium.mojo.bindings.ServiceHandle<%s>" % GetNameForKind(kind) | |
| 132 if isinstance(kind, mojom.Enum): | |
| 133 return "int" | |
| 134 return _spec_to_java_type[kind.spec] | |
| 135 | |
| 136 def TranslateConstants(token, module): | |
| 137 if isinstance(token, (mojom.NamedValue, mojom.EnumValue)): | |
| 138 if isinstance(token, mojom.EnumValue): | |
| 139 entity_value = token.enum_name + '.' + token.name | |
| 140 else: | |
| 141 entity_value = ConstantName(token) | |
| 142 if not token.parent_kind: | |
| 143 entity_value = (GetConstantsMainEntityName(token.module) + | |
| 144 '.' + entity_value) | |
| 145 if token.parent_kind: | |
| 146 return GetJavaType(token.parent_kind) + '.' + entity_value | |
| 147 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
| |
| 148 return token | |
| 149 | |
| 150 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
| |
| 151 if value[0] != "EXPRESSION": | |
| 152 raise Exception("Expected EXPRESSION, got" + value) | |
| 153 return "".join(generator.ExpressionMapper(value, | |
| 154 lambda token: TranslateConstants(token, module))) | |
| 155 | |
| 156 def CapitalizeFirst(string): | |
| 157 return string[0].upper() + string[1:] | |
| 158 | |
| 159 def CamelCase(string): | |
| 160 elements = string.split('_') | |
| 161 return elements[0] + ''.join([x.capitalize() for x in elements[1:]]) | |
| 162 | |
| 163 def UpperCaseConstant(name): | |
| 164 def _IsCut(i): | |
| 165 if i == 0 or i == len(name): | |
| 166 return True | |
| 167 if name[i].islower(): | |
| 168 return False | |
| 169 if name[i-1].isupper() and (i == len(name) -1 or name[i+1].isupper()): | |
| 170 return False | |
| 171 return True | |
| 172 pos = [i for i in xrange(len(name) + 1) if _IsCut(i)] | |
| 173 parts = [name[pos[j]:pos[j+1]] for j in xrange(len(pos)-1)] | |
| 174 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.
| |
| 175 | |
| 176 def DefaultValueConstant(field): | |
| 177 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.
| |
| 178 | |
| 179 def FieldName(field): | |
| 180 return 'm' + GetName(field) | |
| 181 | |
| 182 def ConstantName(constant): | |
| 183 main_name = constant.name | |
| 184 if main_name[0] == 'k': | |
| 185 main_name = main_name[1:] | |
| 186 return UpperCaseConstant(main_name) | |
| 187 | |
| 188 def IsPointerArrayKind(kind): | |
|
rmcilroy
2014/05/25 22:55:10
Please remove IsPointerArrayKind, GetResponseStruc
qsr
2014/05/26 08:41:20
Done.
| |
| 189 if not isinstance(kind, mojom.Array): | |
| 190 return False | |
| 191 sub_kind = kind.kind | |
| 192 return generator.IsObjectKind(sub_kind) | |
| 193 | |
| 194 def GetResponseStructFromMethod(method): | |
| 195 return generator.GetDataHeader( | |
| 196 False, generator.GetResponseStructFromMethod(method)) | |
| 197 | |
| 198 def GetStructFromMethod(method): | |
| 199 return generator.GetDataHeader( | |
| 200 False, generator.GetStructFromMethod(method)) | |
| 201 | |
| 202 def GetMethodName(method): | |
| 203 return (UpperCaseConstant(method.interface.name) + "_" + | |
| 204 UpperCaseConstant(method.name) + "_NAME") | |
| 205 | |
| 206 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.
| |
| 207 package = GetPackage(module) | |
| 208 return GetPackage(module) + '.' + GetConstantsMainEntityName(module) | |
| 209 | |
| 210 def GetConstantsMainEntityName(module): | |
| 211 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
| |
| 212 'Constants') | |
| 213 | |
| 214 class Generator(generator.Generator): | |
| 215 | |
| 216 java_filters = { | |
| 217 "camelcase": CamelCase, | |
| 218 "capitalize_first": CapitalizeFirst, | |
| 219 "default_value_constant": DefaultValueConstant, | |
| 220 "decode_method": DecodeMethod, | |
| 221 "expression_to_text": ExpressionToText, | |
| 222 "field_name": FieldName, | |
| 223 "flags": GetFlags, | |
| 224 "is_bool": lambda kind: kind == mojom.BOOL, | |
| 225 "is_array_kind": lambda kind: isinstance(kind, mojom.Array), | |
| 226 "is_object_kind": generator.IsObjectKind, | |
| 227 "is_pointer_array_kind": IsPointerArrayKind, | |
| 228 "is_string_kind": generator.IsStringKind, | |
| 229 "is_struct_kind": lambda kind: isinstance(kind, mojom.Struct), | |
| 230 "java_getter_prefix": GetJavaGetterPrefix, | |
| 231 "java_type": GetJavaType, | |
| 232 "method_name": GetMethodName, | |
| 233 "new_array": NewArray, | |
| 234 "response_struct_from_method": GetResponseStructFromMethod, | |
| 235 "struct_from_method": GetStructFromMethod, | |
| 236 "struct_size": lambda ps: ps.GetTotalSize() + _HEADER_SIZE, | |
| 237 "super_class": GetSuperClass, | |
| 238 "constant_name": ConstantName, | |
| 239 "verify_token_type": generator.VerifyTokenType, | |
| 240 } | |
| 241 | |
| 242 def GetJinjaExports(self): | |
| 243 return { | |
| 244 "interfaces": self.module.interfaces, | |
| 245 "kinds": self.module.kinds, | |
| 246 "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.
| |
| 247 "module": self.module, | |
| 248 "namespace": self.module.namespace, | |
| 249 "package": GetPackage(self.module), | |
| 250 } | |
| 251 | |
| 252 @UseJinja("java_templates/constants.java.tmpl", filters=java_filters, | |
| 253 lstrip_blocks=True, trim_blocks=True) | |
| 254 def GenerateConstantsSource(self, module): | |
| 255 exports = self.GetJinjaExports() | |
| 256 exports.update({"main_entity": GetConstantsMainEntityName(module), | |
| 257 "constants": module.constants}) | |
| 258 return exports | |
| 259 | |
| 260 def GenerateFiles(self, unparsed_args): | |
| 261 parser = argparse.ArgumentParser() | |
| 262 parser.add_argument("--java_output_directory", dest="java_output_directory") | |
| 263 args = parser.parse_args(unparsed_args) | |
| 264 if self.output_dir and args.java_output_directory: | |
| 265 self.output_dir = os.path.join(args.java_output_directory, | |
| 266 GetPackage(self.module).replace('.', '/')) | |
| 267 if not os.path.exists(self.output_dir): | |
| 268 os.makedirs(self.output_dir) | |
| 269 | |
| 270 if self.module.constants: | |
| 271 self.Write(self.GenerateConstantsSource(self.module), | |
| 272 "%s.java" % GetConstantsMainEntityName(self.module)) | |
| OLD | NEW |