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 |