OLD | NEW |
| (Empty) |
1 # Copyright 2014 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 dart source files from a mojom.Module.""" | |
6 | |
7 import errno | |
8 import os | |
9 import re | |
10 import shutil | |
11 import sys | |
12 | |
13 import mojom.fileutil as fileutil | |
14 import mojom.generate.constant_resolver as resolver | |
15 import mojom.generate.generator as generator | |
16 import mojom.generate.module as mojom | |
17 import mojom.generate.pack as pack | |
18 from mojom.generate.template_expander import UseJinja | |
19 | |
20 GENERATOR_PREFIX = 'dart' | |
21 | |
22 # CAUTION: To generate Dart-style names, and to avoid generating reserved words | |
23 # for identifiers, the template files should generate names using | |
24 # {{element|name}}, not {{element.name}}. | |
25 | |
26 # Dart reserved words from: | |
27 # http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf | |
28 # We must not generate reserved words for identifiers. | |
29 # NB: async, await, and yield are not technically reserved words, but since | |
30 # they are not valid identifiers in all contexts, we include them here as well. | |
31 _dart_reserved_words = [ | |
32 "assert", | |
33 "async", | |
34 "await", | |
35 "break", | |
36 "case", | |
37 "catch", | |
38 "class", | |
39 "const", | |
40 "continue", | |
41 "default", | |
42 "do", | |
43 "else", | |
44 "enum", | |
45 "extends", | |
46 "false", | |
47 "final", | |
48 "finally", | |
49 "for", | |
50 "if", | |
51 "in", | |
52 "is", | |
53 "new", | |
54 "null", | |
55 "rethrow", | |
56 "return", | |
57 "super", | |
58 "switch", | |
59 "this", | |
60 "throw", | |
61 "true", | |
62 "try", | |
63 "var", | |
64 "void", | |
65 "while", | |
66 "with", | |
67 "yield", | |
68 ] | |
69 | |
70 # These names are the class fields and methods of the Proxy class in | |
71 # lib/src/proxy.dart of Dart's mojo package. If these names appear in a .mojom | |
72 # they must be mangled to avoid name conflicts. They are mangled by appending | |
73 # an underscore ('_'), which is banned on names in mojom interfaces. | |
74 _reserved_words = _dart_reserved_words + [ | |
75 "close", | |
76 "connectToService", | |
77 "ctrl", | |
78 "fromEndpoint", | |
79 "fromHandle", | |
80 "fromMock", | |
81 "impl", | |
82 "newFromEndpoint", | |
83 "responseOrError", | |
84 "serviceDescription", | |
85 "serviceName", | |
86 "unbound", | |
87 ] | |
88 | |
89 _kind_to_dart_default_value = { | |
90 mojom.BOOL: "false", | |
91 mojom.INT8: "0", | |
92 mojom.UINT8: "0", | |
93 mojom.INT16: "0", | |
94 mojom.UINT16: "0", | |
95 mojom.INT32: "0", | |
96 mojom.UINT32: "0", | |
97 mojom.FLOAT: "0.0", | |
98 mojom.HANDLE: "null", | |
99 mojom.DCPIPE: "null", | |
100 mojom.DPPIPE: "null", | |
101 mojom.MSGPIPE: "null", | |
102 mojom.SHAREDBUFFER: "null", | |
103 mojom.NULLABLE_HANDLE: "null", | |
104 mojom.NULLABLE_DCPIPE: "null", | |
105 mojom.NULLABLE_DPPIPE: "null", | |
106 mojom.NULLABLE_MSGPIPE: "null", | |
107 mojom.NULLABLE_SHAREDBUFFER: "null", | |
108 mojom.INT64: "0", | |
109 mojom.UINT64: "0", | |
110 mojom.DOUBLE: "0.0", | |
111 mojom.STRING: "null", | |
112 mojom.NULLABLE_STRING: "null" | |
113 } | |
114 | |
115 _kind_to_dart_decl_type = { | |
116 mojom.BOOL: "bool", | |
117 mojom.INT8: "int", | |
118 mojom.UINT8: "int", | |
119 mojom.INT16: "int", | |
120 mojom.UINT16: "int", | |
121 mojom.INT32: "int", | |
122 mojom.UINT32: "int", | |
123 mojom.FLOAT: "double", | |
124 mojom.HANDLE: "core.MojoHandle", | |
125 mojom.DCPIPE: "core.MojoDataPipeConsumer", | |
126 mojom.DPPIPE: "core.MojoDataPipeProducer", | |
127 mojom.MSGPIPE: "core.MojoMessagePipeEndpoint", | |
128 mojom.SHAREDBUFFER: "core.MojoSharedBuffer", | |
129 mojom.NULLABLE_HANDLE: "core.MojoHandle", | |
130 mojom.NULLABLE_DCPIPE: "core.MojoDataPipeConsumer", | |
131 mojom.NULLABLE_DPPIPE: "core.MojoDataPipeProducer", | |
132 mojom.NULLABLE_MSGPIPE: "core.MojoMessagePipeEndpoint", | |
133 mojom.NULLABLE_SHAREDBUFFER: "core.MojoSharedBuffer", | |
134 mojom.INT64: "int", | |
135 mojom.UINT64: "int", | |
136 mojom.DOUBLE: "double", | |
137 mojom.STRING: "String", | |
138 mojom.NULLABLE_STRING: "String" | |
139 } | |
140 | |
141 _spec_to_decode_method = { | |
142 mojom.BOOL.spec: 'decodeBool', | |
143 mojom.DCPIPE.spec: 'decodeConsumerHandle', | |
144 mojom.DOUBLE.spec: 'decodeDouble', | |
145 mojom.DPPIPE.spec: 'decodeProducerHandle', | |
146 mojom.FLOAT.spec: 'decodeFloat', | |
147 mojom.HANDLE.spec: 'decodeHandle', | |
148 mojom.INT16.spec: 'decodeInt16', | |
149 mojom.INT32.spec: 'decodeInt32', | |
150 mojom.INT64.spec: 'decodeInt64', | |
151 mojom.INT8.spec: 'decodeInt8', | |
152 mojom.MSGPIPE.spec: 'decodeMessagePipeHandle', | |
153 mojom.NULLABLE_DCPIPE.spec: 'decodeConsumerHandle', | |
154 mojom.NULLABLE_DPPIPE.spec: 'decodeProducerHandle', | |
155 mojom.NULLABLE_HANDLE.spec: 'decodeHandle', | |
156 mojom.NULLABLE_MSGPIPE.spec: 'decodeMessagePipeHandle', | |
157 mojom.NULLABLE_SHAREDBUFFER.spec: 'decodeSharedBufferHandle', | |
158 mojom.NULLABLE_STRING.spec: 'decodeString', | |
159 mojom.SHAREDBUFFER.spec: 'decodeSharedBufferHandle', | |
160 mojom.STRING.spec: 'decodeString', | |
161 mojom.UINT16.spec: 'decodeUint16', | |
162 mojom.UINT32.spec: 'decodeUint32', | |
163 mojom.UINT64.spec: 'decodeUint64', | |
164 mojom.UINT8.spec: 'decodeUint8', | |
165 } | |
166 | |
167 _spec_to_encode_method = { | |
168 mojom.BOOL.spec: 'encodeBool', | |
169 mojom.DCPIPE.spec: 'encodeConsumerHandle', | |
170 mojom.DOUBLE.spec: 'encodeDouble', | |
171 mojom.DPPIPE.spec: 'encodeProducerHandle', | |
172 mojom.FLOAT.spec: 'encodeFloat', | |
173 mojom.HANDLE.spec: 'encodeHandle', | |
174 mojom.INT16.spec: 'encodeInt16', | |
175 mojom.INT32.spec: 'encodeInt32', | |
176 mojom.INT64.spec: 'encodeInt64', | |
177 mojom.INT8.spec: 'encodeInt8', | |
178 mojom.MSGPIPE.spec: 'encodeMessagePipeHandle', | |
179 mojom.NULLABLE_DCPIPE.spec: 'encodeConsumerHandle', | |
180 mojom.NULLABLE_DPPIPE.spec: 'encodeProducerHandle', | |
181 mojom.NULLABLE_HANDLE.spec: 'encodeHandle', | |
182 mojom.NULLABLE_MSGPIPE.spec: 'encodeMessagePipeHandle', | |
183 mojom.NULLABLE_SHAREDBUFFER.spec: 'encodeSharedBufferHandle', | |
184 mojom.NULLABLE_STRING.spec: 'encodeString', | |
185 mojom.SHAREDBUFFER.spec: 'encodeSharedBufferHandle', | |
186 mojom.STRING.spec: 'encodeString', | |
187 mojom.UINT16.spec: 'encodeUint16', | |
188 mojom.UINT32.spec: 'encodeUint32', | |
189 mojom.UINT64.spec: 'encodeUint64', | |
190 mojom.UINT8.spec: 'encodeUint8', | |
191 } | |
192 | |
193 # The mojom_types.mojom and service_describer.mojom files are special because | |
194 # they are used to generate mojom Type's and ServiceDescription implementations. | |
195 # They need to be imported, unless the file itself is being generated. | |
196 _service_describer_pkg_short = "service_describer" | |
197 _service_describer_pkg = "package:mojo/mojo/bindings/types/%s.mojom.dart" % \ | |
198 _service_describer_pkg_short | |
199 _mojom_types_pkg_short = "mojom_types" | |
200 _mojom_types_pkg = "package:mojo/mojo/bindings/types/%s.mojom.dart" % \ | |
201 _mojom_types_pkg_short | |
202 | |
203 def GetDartType(kind): | |
204 if kind.imported_from: | |
205 return kind.imported_from["unique_name"] + "." + GetNameForElement(kind) | |
206 return GetNameForElement(kind) | |
207 | |
208 def DartDefaultValue(field): | |
209 if field.default: | |
210 if mojom.IsStructKind(field.kind): | |
211 assert field.default == "default" | |
212 return "new %s()" % GetDartType(field.kind) | |
213 if mojom.IsEnumKind(field.kind): | |
214 return ("new %s(%s)" % | |
215 (GetDartType(field.kind), ExpressionToText(field.default))) | |
216 return ExpressionToText(field.default) | |
217 if field.kind in mojom.PRIMITIVES: | |
218 return _kind_to_dart_default_value[field.kind] | |
219 if mojom.IsStructKind(field.kind): | |
220 return "null" | |
221 if mojom.IsUnionKind(field.kind): | |
222 return "null" | |
223 if mojom.IsArrayKind(field.kind): | |
224 return "null" | |
225 if mojom.IsMapKind(field.kind): | |
226 return "null" | |
227 if mojom.IsInterfaceKind(field.kind) or \ | |
228 mojom.IsInterfaceRequestKind(field.kind): | |
229 return "null" | |
230 if mojom.IsEnumKind(field.kind): | |
231 return "null" | |
232 | |
233 def DartDeclType(kind): | |
234 if kind in mojom.PRIMITIVES: | |
235 return _kind_to_dart_decl_type[kind] | |
236 if mojom.IsStructKind(kind): | |
237 return GetDartType(kind) | |
238 if mojom.IsUnionKind(kind): | |
239 return GetDartType(kind) | |
240 if mojom.IsArrayKind(kind): | |
241 array_type = DartDeclType(kind.kind) | |
242 return "List<" + array_type + ">" | |
243 if mojom.IsMapKind(kind): | |
244 key_type = DartDeclType(kind.key_kind) | |
245 value_type = DartDeclType(kind.value_kind) | |
246 return "Map<"+ key_type + ", " + value_type + ">" | |
247 if mojom.IsInterfaceKind(kind): | |
248 return ("%sInterface" % GetDartType(kind)) | |
249 if mojom.IsInterfaceRequestKind(kind): | |
250 return ("%sInterfaceRequest" % GetDartType(kind.kind)) | |
251 if mojom.IsEnumKind(kind): | |
252 return GetDartType(kind) | |
253 | |
254 def NameToComponent(name): | |
255 # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> | |
256 # HTTP_Entry2_FooBar). Numbers terminate a string of lower-case characters. | |
257 name = re.sub('([^_])([A-Z][^A-Z1-9_]+)', r'\1_\2', name) | |
258 # insert '_' between non upper and start of upper blocks (e.g., | |
259 # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar). | |
260 name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name) | |
261 return [x.lower() for x in name.split('_')] | |
262 | |
263 def UpperCamelCase(name): | |
264 return ''.join([x.capitalize() for x in NameToComponent(name)]) | |
265 | |
266 def CamelCase(name): | |
267 uccc = UpperCamelCase(name) | |
268 return uccc[0].lower() + uccc[1:] | |
269 | |
270 def DotToUnderscore(name): | |
271 return name.replace('.', '_') | |
272 | |
273 def IsParamStruct(kind): | |
274 assert(isinstance(kind, mojom.Struct)) | |
275 return kind.name.endswith('_Params') | |
276 | |
277 # This may generate Dart reserved words. Call GetNameForElement to avoid | |
278 # generating reserved words. | |
279 def GetNameForElementUnsafe(element): | |
280 if (mojom.IsInterfaceKind(element) or mojom.IsUnionKind(element)): | |
281 return UpperCamelCase(element.name) | |
282 if mojom.IsStructKind(element): | |
283 if (IsParamStruct(element)): | |
284 # Param Structs are library private. | |
285 return '_' + UpperCamelCase(element.name) | |
286 return UpperCamelCase(element.name) | |
287 if mojom.IsInterfaceRequestKind(element): | |
288 return GetNameForElement(element.kind) | |
289 if isinstance(element, (mojom.Constant, | |
290 mojom.EnumField, | |
291 mojom.Field, | |
292 mojom.Method, | |
293 mojom.NamedValue, | |
294 mojom.Parameter, | |
295 mojom.UnionField)): | |
296 return CamelCase(element.name) | |
297 if mojom.IsEnumKind(element): | |
298 # If the enum is nested in some other mojom element, then we | |
299 # mangle the enum name by prepending it with the name of the containing | |
300 # element. | |
301 if element.parent_kind: | |
302 return ("%s%s" % (GetNameForElement(element.parent_kind), | |
303 UpperCamelCase(element.name))) | |
304 return UpperCamelCase(element.name) | |
305 if isinstance(element, mojom.EnumValue): | |
306 return (GetNameForElement(element.enum) + '.' + CamelCase(element.name)) | |
307 raise Exception('Unexpected element: %s' % element) | |
308 | |
309 def GetNameForElement(element): | |
310 name = GetNameForElementUnsafe(element) | |
311 if name in _reserved_words: | |
312 name = name + '_' | |
313 return name | |
314 | |
315 def GetInterfaceResponseName(method): | |
316 return UpperCamelCase(method.name + 'Response') | |
317 | |
318 def GetDartTrueFalse(value): | |
319 return 'true' if value else 'false' | |
320 | |
321 def GetArrayNullabilityFlags(kind): | |
322 """Returns nullability flags for an array type, see codec.dart. | |
323 | |
324 As we have dedicated decoding functions for arrays, we have to pass | |
325 nullability information about both the array itself, as well as the array | |
326 element type there. | |
327 """ | |
328 assert mojom.IsArrayKind(kind) | |
329 ARRAY_NULLABLE = 'bindings.kArrayNullable' | |
330 ELEMENT_NULLABLE = 'bindings.kElementNullable' | |
331 NOTHING_NULLABLE = 'bindings.kNothingNullable' | |
332 | |
333 flags_to_set = [] | |
334 if mojom.IsNullableKind(kind): | |
335 flags_to_set.append(ARRAY_NULLABLE) | |
336 if mojom.IsNullableKind(kind.kind): | |
337 flags_to_set.append(ELEMENT_NULLABLE) | |
338 | |
339 if not flags_to_set: | |
340 flags_to_set = [NOTHING_NULLABLE] | |
341 return ' | '.join(flags_to_set) | |
342 | |
343 def AppendDecodeParams(initial_params, kind, bit): | |
344 """ Appends standard parameters for decode calls. """ | |
345 params = list(initial_params) | |
346 if (kind == mojom.BOOL): | |
347 params.append(str(bit)) | |
348 if mojom.IsReferenceKind(kind): | |
349 if mojom.IsArrayKind(kind): | |
350 params.append(GetArrayNullabilityFlags(kind)) | |
351 else: | |
352 params.append(GetDartTrueFalse(mojom.IsNullableKind(kind))) | |
353 if mojom.IsInterfaceKind(kind): | |
354 params.append('%sProxy.newFromEndpoint' % GetDartType(kind)) | |
355 if mojom.IsArrayKind(kind) and mojom.IsInterfaceKind(kind.kind): | |
356 params.append('%sProxy.newFromEndpoint' % GetDartType(kind.kind)) | |
357 if mojom.IsInterfaceRequestKind(kind): | |
358 params.append('%sStub.newFromEndpoint' % GetDartType(kind.kind)) | |
359 if mojom.IsArrayKind(kind) and mojom.IsInterfaceRequestKind(kind.kind): | |
360 params.append('%sStub.newFromEndpoint' % GetDartType(kind.kind.kind)) | |
361 if mojom.IsArrayKind(kind): | |
362 params.append(GetArrayExpectedLength(kind)) | |
363 return params | |
364 | |
365 def AppendEncodeParams(initial_params, kind, bit): | |
366 """ Appends standard parameters shared between encode and decode calls. """ | |
367 params = list(initial_params) | |
368 if (kind == mojom.BOOL): | |
369 params.append(str(bit)) | |
370 if mojom.IsReferenceKind(kind): | |
371 if mojom.IsArrayKind(kind): | |
372 params.append(GetArrayNullabilityFlags(kind)) | |
373 else: | |
374 params.append(GetDartTrueFalse(mojom.IsNullableKind(kind))) | |
375 if mojom.IsArrayKind(kind): | |
376 params.append(GetArrayExpectedLength(kind)) | |
377 return params | |
378 | |
379 def DecodeMethod(kind, offset, bit): | |
380 def _DecodeMethodName(kind): | |
381 if mojom.IsArrayKind(kind): | |
382 return _DecodeMethodName(kind.kind) + 'Array' | |
383 if mojom.IsInterfaceRequestKind(kind): | |
384 return 'decodeInterfaceRequest' | |
385 if mojom.IsInterfaceKind(kind): | |
386 return 'decodeServiceInterface' | |
387 return _spec_to_decode_method[kind.spec] | |
388 methodName = _DecodeMethodName(kind) | |
389 params = AppendDecodeParams([ str(offset) ], kind, bit) | |
390 return '%s(%s)' % (methodName, ', '.join(params)) | |
391 | |
392 def EncodeMethod(kind, variable, offset, bit): | |
393 def _EncodeMethodName(kind): | |
394 if mojom.IsStructKind(kind): | |
395 return 'encodeStruct' | |
396 if mojom.IsUnionKind(kind): | |
397 return 'encodeUnion' | |
398 if mojom.IsArrayKind(kind): | |
399 return _EncodeMethodName(kind.kind) + 'Array' | |
400 if mojom.IsEnumKind(kind): | |
401 return 'encodeEnum' | |
402 if mojom.IsInterfaceRequestKind(kind): | |
403 return 'encodeInterfaceRequest' | |
404 if mojom.IsInterfaceKind(kind): | |
405 return 'encodeInterface' | |
406 return _spec_to_encode_method[kind.spec] | |
407 methodName = _EncodeMethodName(kind) | |
408 params = AppendEncodeParams([ variable, str(offset) ], kind, bit) | |
409 return '%s(%s)' % (methodName, ', '.join(params)) | |
410 | |
411 def TranslateConstants(token): | |
412 if isinstance(token, mojom.BuiltinValue): | |
413 if token.value == "double.INFINITY" or token.value == "float.INFINITY": | |
414 return "double.INFINITY"; | |
415 if token.value == "double.NEGATIVE_INFINITY" or \ | |
416 token.value == "float.NEGATIVE_INFINITY": | |
417 return "double.NEGATIVE_INFINITY"; | |
418 if token.value == "double.NAN" or token.value == "float.NAN": | |
419 return "double.NAN"; | |
420 | |
421 # Strip leading '+'. | |
422 if token[0] == '+': | |
423 token = token[1:] | |
424 | |
425 return token | |
426 | |
427 def ExpressionToText(token): | |
428 if isinstance(token, (mojom.EnumValue, mojom.NamedValue)): | |
429 return str(token.resolved_value) | |
430 return TranslateConstants(token) | |
431 | |
432 def GetArrayKind(kind, size = None): | |
433 if size is None: | |
434 return mojom.Array(kind) | |
435 else: | |
436 array = mojom.Array(kind, 0) | |
437 array.dart_map_size = size | |
438 return array | |
439 | |
440 def GetArrayExpectedLength(kind): | |
441 if mojom.IsArrayKind(kind) and kind.length is not None: | |
442 return getattr(kind, 'dart_map_size', str(kind.length)) | |
443 else: | |
444 return 'bindings.kUnspecifiedArrayLength' | |
445 | |
446 def IsPointerArrayKind(kind): | |
447 if not mojom.IsArrayKind(kind): | |
448 return False | |
449 sub_kind = kind.kind | |
450 return mojom.IsObjectKind(sub_kind) | |
451 | |
452 def IsEnumArrayKind(kind): | |
453 return mojom.IsArrayKind(kind) and mojom.IsEnumKind(kind.kind) | |
454 | |
455 def IsImportedKind(kind): | |
456 return hasattr(kind, 'imported_from') and kind.imported_from | |
457 | |
458 def ParseStringAttribute(attribute): | |
459 assert isinstance(attribute, basestring) | |
460 return attribute | |
461 | |
462 def GetPackage(module): | |
463 if module.attributes and 'DartPackage' in module.attributes: | |
464 package = ParseStringAttribute(module.attributes['DartPackage']) | |
465 package = package.strip() | |
466 if package != '': | |
467 return package | |
468 # Default package. | |
469 return 'mojom' | |
470 | |
471 def GetImportUri(module): | |
472 package = GetPackage(module); | |
473 elements = module.namespace.split('.') | |
474 elements.append("%s" % module.name) | |
475 return os.path.join(package, *elements) | |
476 | |
477 def RaiseHelper(msg): | |
478 raise Exception(msg) | |
479 | |
480 class Generator(generator.Generator): | |
481 | |
482 dart_filters = { | |
483 'array_expected_length': GetArrayExpectedLength, | |
484 'array': GetArrayKind, | |
485 'decode_method': DecodeMethod, | |
486 'default_value': DartDefaultValue, | |
487 'encode_method': EncodeMethod, | |
488 'is_imported_kind': IsImportedKind, | |
489 'is_array_kind': mojom.IsArrayKind, | |
490 'is_map_kind': mojom.IsMapKind, | |
491 'is_numerical_kind': mojom.IsNumericalKind, | |
492 'is_any_handle_kind': mojom.IsAnyHandleKind, | |
493 'is_string_kind': mojom.IsStringKind, | |
494 'is_nullable_kind': mojom.IsNullableKind, | |
495 'is_pointer_array_kind': IsPointerArrayKind, | |
496 'is_enum_array_kind': IsEnumArrayKind, | |
497 'is_struct_kind': mojom.IsStructKind, | |
498 'is_union_kind': mojom.IsUnionKind, | |
499 'is_enum_kind': mojom.IsEnumKind, | |
500 'is_interface_kind': mojom.IsInterfaceKind, | |
501 'is_interface_request_kind': mojom.IsInterfaceRequestKind, | |
502 'dart_true_false': GetDartTrueFalse, | |
503 'dart_type': DartDeclType, | |
504 'name': GetNameForElement, | |
505 'interface_response_name': GetInterfaceResponseName, | |
506 'dot_to_underscore': DotToUnderscore, | |
507 'is_cloneable_kind': mojom.IsCloneableKind, | |
508 'upper_camel': UpperCamelCase, | |
509 'lower_camel': CamelCase, | |
510 'raise': RaiseHelper, | |
511 } | |
512 | |
513 # If set to True, then mojom type information will be generated. | |
514 should_gen_mojom_types = False | |
515 | |
516 def GetParameters(self, args): | |
517 package = self.module.name.split('.')[0] | |
518 | |
519 # True if handles are used anywhere in the mojom. | |
520 has_handles = any(not mojom.IsCloneableKind(kind) | |
521 for kind in (self.GetStructs() + | |
522 self.GetStructsFromMethods() + | |
523 self.GetUnions())) | |
524 | |
525 # True if the binding will need dart:async | |
526 needs_dart_async = any(any(method.response_parameters is not None | |
527 for method in interface.methods) | |
528 for interface in self.GetInterfaces()) | |
529 | |
530 parameters = { | |
531 "namespace": self.module.namespace, | |
532 "imports": self.GetImports(args), | |
533 "kinds": self.module.kinds, | |
534 "enums": self.module.enums, | |
535 "module": resolver.ResolveConstants(self.module, ExpressionToText), | |
536 "structs": self.GetStructs() + self.GetStructsFromMethods(), | |
537 "unions": self.GetUnions(), | |
538 "interfaces": self.GetInterfaces(), | |
539 "imported_interfaces": self.GetImportedInterfaces(), | |
540 "imported_from": self.ImportedFrom(), | |
541 "typepkg": '%s.' % _mojom_types_pkg_short, | |
542 "descpkg": '%s.' % _service_describer_pkg_short, | |
543 "mojom_types_import": 'import \'%s\' as %s;' % \ | |
544 (_mojom_types_pkg, _mojom_types_pkg_short), | |
545 "service_describer_import": 'import \'%s\' as %s;' % \ | |
546 (_service_describer_pkg, _service_describer_pkg_short), | |
547 "has_handles": has_handles, | |
548 "needs_dart_async": needs_dart_async, | |
549 } | |
550 | |
551 # If this is the mojom types package, clear the import-related params. | |
552 if package == _mojom_types_pkg_short: | |
553 parameters["typepkg"] = "" | |
554 parameters["mojom_types_import"] = "" | |
555 | |
556 # If this is the service describer package, clear the import-related params. | |
557 if package == _service_describer_pkg_short: | |
558 parameters["descpkg"] = "" | |
559 parameters["service_describer_import"] = "" | |
560 | |
561 # If no interfaces were defined, the service describer import isn't needed. | |
562 if len(self.module.interfaces) == 0: | |
563 parameters["service_describer_import"] = "" | |
564 | |
565 return parameters | |
566 | |
567 def GetGlobals(self): | |
568 return { | |
569 'should_gen_mojom_types': self.should_gen_mojom_types, | |
570 } | |
571 | |
572 @UseJinja("dart_templates/module.lib.tmpl", filters=dart_filters) | |
573 def GenerateLibModule(self, args): | |
574 return self.GetParameters(args) | |
575 | |
576 | |
577 def GenerateFiles(self, args): | |
578 self.should_gen_mojom_types = "--generate_type_info" in args | |
579 | |
580 elements = self.module.namespace.split('.') | |
581 elements.append("%s.dart" % self.module.name) | |
582 | |
583 lib_module = self.GenerateLibModule(args) | |
584 | |
585 # List of packages with checked in bindings. | |
586 # TODO(johnmccutchan): Stop generating bindings as part of build system | |
587 # and then remove this. | |
588 packages_with_checked_in_bindings = [ | |
589 '_mojo_for_test_only', | |
590 'mojo', | |
591 'mojo_apptest', | |
592 'mojo_services', | |
593 'mojo_sdk', | |
594 'mojom', | |
595 ] | |
596 package_name = GetPackage(self.module) | |
597 if not (package_name in packages_with_checked_in_bindings): | |
598 pkg_path = os.path.join("dart-pkg", package_name, "lib", *elements) | |
599 self.Write(lib_module, pkg_path) | |
600 | |
601 gen_path = os.path.join("dart-gen", package_name, "lib", *elements) | |
602 full_gen_path = os.path.join(self.output_dir, gen_path) | |
603 self.Write(lib_module, gen_path) | |
604 | |
605 link = self.MatchMojomFilePath("%s.dart" % self.module.name) | |
606 full_link_path = os.path.join(self.output_dir, link) | |
607 try: | |
608 os.unlink(full_link_path) | |
609 except OSError, exc: | |
610 # If the file does not exist, ignore the error. | |
611 if errno.ENOENT == exc.errno: | |
612 pass | |
613 else: | |
614 raise | |
615 fileutil.EnsureDirectoryExists(os.path.dirname(full_link_path)) | |
616 try: | |
617 if sys.platform == "win32": | |
618 shutil.copy(full_gen_path, full_link_path) | |
619 else: | |
620 os.symlink(full_gen_path, full_link_path) | |
621 except OSError as e: | |
622 # Errno 17 is file already exists. If the link fails because file already | |
623 # exists assume another instance of this script tried to create the same | |
624 # file and continue on. | |
625 if e.errno != 17: | |
626 raise e | |
627 | |
628 def GetImports(self, args): | |
629 used_imports = self.GetUsedImports(self.module) | |
630 used_names = set() | |
631 for each_import in used_imports.values(): | |
632 simple_name = each_import["module_name"].split(".")[0] | |
633 | |
634 # Since each import is assigned a library in Dart, they need to have | |
635 # unique names. | |
636 unique_name = simple_name | |
637 counter = 0 | |
638 while unique_name in used_names: | |
639 counter += 1 | |
640 unique_name = simple_name + str(counter) | |
641 | |
642 used_names.add(unique_name) | |
643 each_import["unique_name"] = unique_name + '_mojom' | |
644 counter += 1 | |
645 | |
646 each_import["rebased_path"] = GetImportUri(each_import['module']) | |
647 return sorted(used_imports.values(), key=lambda x: x['rebased_path']) | |
648 | |
649 def GetImportedInterfaces(self): | |
650 interface_to_import = {} | |
651 for each_import in self.module.imports: | |
652 for each_interface in each_import["module"].interfaces: | |
653 name = each_interface.name | |
654 interface_to_import[name] = each_import["unique_name"] + "." + name | |
655 return interface_to_import | |
656 | |
657 def ImportedFrom(self): | |
658 interface_to_import = {} | |
659 for each_import in self.module.imports: | |
660 for each_interface in each_import["module"].interfaces: | |
661 name = each_interface.name | |
662 interface_to_import[name] = each_import["unique_name"] + "." | |
663 return interface_to_import | |
OLD | NEW |