OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright 2015 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 # | |
6 # This module is responsible for translating a MojomFileGraph (see | |
7 # mojom_files.mojom) to one or more module.Module. | |
8 # | |
9 # This module takes the output of the mojom parser, a MojomFileGraph and | |
10 # translates it to the input of the code generators, a module.Module object. | |
11 # This is part of version 2 of the code generation pipeline. In version 1, the | |
12 # analogous functionality (translating from parser output to code generators | |
13 # input) is performed by the data module. | |
14 # | |
15 # The code generators remain from version 1 of the pipeline and so this module | |
16 # serves as an adapter between the v1 backends and the v2 frontend. | |
17 # | |
18 # The current version of this script does not validate the input data at all | |
19 # and instead trusts that it will be invoked with valid data produced by the | |
20 # frontend parser. | |
21 # | |
22 # NOTE: This module assumes that the python path contains the generated modules | |
23 # for mojom_files.mojom and mojom_types.mojom as well as their dependencies. | |
24 # It is the responsibility of the module's loader to handle this. | |
25 | |
26 import os | |
27 | |
28 from generated import mojom_files_mojom | |
29 from generated import mojom_types_mojom | |
30 import module | |
31 import operator | |
32 import pack | |
33 | |
34 | |
35 class FileTranslator(object): | |
36 """FileTranslator translates a MojomFile to a module.Module.""" | |
37 def __init__(self, graph, file_name): | |
38 """Initializes a FileTranslator. | |
39 | |
40 Args: | |
41 graph: {mojom_files_mojom.MojomFileGraph} containing the file to be | |
42 translated. | |
43 file_name: {str} key to the file to be translated in graph.files. | |
44 """ | |
45 assert isinstance(graph, mojom_files_mojom.MojomFileGraph) | |
46 self._type_cache = {} | |
47 self._value_cache = {} | |
48 self._constant_cache = {} | |
49 self._graph = graph | |
50 self._file_name = file_name | |
51 self._types = {} | |
52 self._module = module.Module() | |
53 self._transitive_imports = {} | |
54 | |
55 def Translate(self): | |
56 """Translates the file specified in the constructor. | |
57 | |
58 Returns: | |
59 {module.Module} representing the translated file. | |
60 """ | |
61 mojom_file = self._graph.files[self._file_name] | |
62 | |
63 mod = self._module | |
64 self.PopulateModuleMetadata(mod, mojom_file) | |
65 | |
66 mod.imports = [] | |
67 self._transitive_imports = self.GetTransitiveImports(mojom_file) | |
68 mod.transitive_imports = self._transitive_imports.values() | |
69 if mojom_file.imports: | |
70 mod.imports = [ | |
71 self._transitive_imports[imp] for imp in mojom_file.imports] | |
72 | |
73 if mojom_file.declared_mojom_objects: | |
74 if mojom_file.declared_mojom_objects.top_level_constants: | |
75 mod.constants = [ | |
76 self.ConstantFromKey(key) | |
77 for key in mojom_file.declared_mojom_objects.top_level_constants] | |
78 | |
79 user_defined_types = ['interfaces', 'structs', 'unions'] | |
80 for user_defined_type in user_defined_types: | |
81 if getattr(mojom_file.declared_mojom_objects, user_defined_type): | |
82 setattr(mod, user_defined_type, [self.UserDefinedFromTypeKey(key) | |
83 for key in getattr( | |
84 mojom_file.declared_mojom_objects, user_defined_type)]) | |
85 if mojom_file.declared_mojom_objects.top_level_enums: | |
86 mod.enums = [self.UserDefinedFromTypeKey(key) | |
87 for key in mojom_file.declared_mojom_objects.top_level_enums] | |
88 | |
89 mod.serialized_runtime_type_info = mojom_file.serialized_runtime_type_info | |
90 | |
91 return mod | |
92 | |
93 def PopulateModuleMetadata(self, mod, mojom_file): | |
94 """Populates some fields of a module.Module based on a MojomFile. | |
95 | |
96 Populates name, path, namespace and attributes of mod. | |
97 | |
98 Args: | |
99 mod: {module.Module} the module to be populated. | |
100 mojom_file: {MojomFile} the file to be translated. | |
101 """ | |
102 mod.name = os.path.basename(mojom_file.file_name) | |
103 # specified_file_name is the file name specified on the command line if one | |
104 # was specified. The mojom parser sets specified_file_name to the empty | |
105 # string if the file was parsed only because the file was imported by | |
106 # another file. While specified_file_name can be None, the mojom parser | |
107 # should not set it to None, so we check for that error here. | |
108 assert mojom_file.specified_file_name is not None | |
109 mod.specified_name = mojom_file.specified_file_name | |
110 mod.path = mojom_file.file_name | |
111 mod.namespace = mojom_file.module_namespace | |
112 # Note that attribute values are typed. That is why we use | |
113 # attr.value.data directly instead of the string representation of it. | |
114 if mojom_file.attributes: | |
115 mod.attributes = {attr.key: | |
116 attr.value.data for attr in mojom_file.attributes} | |
117 | |
118 def GetTransitiveImports(self, mojom_file): | |
119 """Gets a mojom file's transitive imports. | |
120 | |
121 Args: | |
122 mojom_file: {mojom_files.MojomFile} the mojom file whose imports have to | |
123 be found. | |
124 | |
125 Returns: | |
126 {dict} The key is the file_name which is an index into self._graph.files | |
127 and is referenced in the SourceFileInfo.file_name of imported types. | |
128 The value is a dictionary as returned by ImportFromMojom. | |
129 """ | |
130 if not mojom_file.imports: | |
131 return {} | |
132 to_be_processed = set(mojom_file.imports) | |
133 processed = set() | |
134 transitive_imports = {} | |
135 | |
136 while to_be_processed: | |
137 import_name = to_be_processed.pop() | |
138 processed.add(import_name) | |
139 | |
140 import_dict = self.ImportFromMojom(import_name) | |
141 | |
142 transitive_imports[import_dict['module'].path] = import_dict | |
143 | |
144 import_file = self._graph.files[import_name] | |
145 if import_file.imports: | |
146 to_be_processed.update(set(import_file.imports) - processed) | |
147 | |
148 return transitive_imports | |
149 | |
150 def ImportFromMojom(self, import_name): | |
151 """Builds a dict representing an import. | |
152 | |
153 Args: | |
154 import_name: {str} key to the imported file in graph.files. | |
155 | |
156 Returns: | |
157 {dict} representing the imported file. | |
158 """ | |
159 import_file = self._graph.files[import_name] | |
160 import_module = module.Module() | |
161 self.PopulateModuleMetadata(import_module, import_file) | |
162 | |
163 import_item = { | |
164 'module_name': import_module.name, | |
165 'namespace': import_module.namespace, | |
166 'module': import_module, | |
167 } | |
168 return import_item | |
169 | |
170 def UnionFromMojom(self, union, mojom_type): | |
171 """Populates a module.Union based on a MojomUnion. | |
172 | |
173 Args: | |
174 union: {module.Union} to be populated. | |
175 mojom_type: {UserDefinedType} referring to the MojomUnion to be | |
176 translated. | |
177 """ | |
178 assert mojom_type.tag == mojom_types_mojom.UserDefinedType.Tags.union_type | |
179 mojom_union = mojom_type.union_type | |
180 self.PopulateUserDefinedType(union, mojom_union) | |
181 union.fields = [self.UnionFieldFromMojom(f) for f in mojom_union.fields] | |
182 # mojom_union.fields is indexed by the field tags. We want | |
183 # to capture these tags but sort union.fields by declaration_order. | |
184 union.fields.sort(key=lambda field: field.declaration_order) | |
185 | |
186 def StructFromMojom(self, struct, mojom_type): | |
187 """Populates a module.Struct based on a MojomStruct. | |
188 | |
189 Args: | |
190 struct: {module.Struct} to be populated. | |
191 mojom_type: {UserDefinedType} referring to the MojomStruct to be | |
192 translated. | |
193 """ | |
194 assert mojom_type.tag == mojom_types_mojom.UserDefinedType.Tags.struct_type | |
195 mojom_struct = mojom_type.struct_type | |
196 self.StructFromMojomStruct(struct, mojom_struct) | |
197 | |
198 def StructFromMojomStruct(self, struct, mojom_struct): | |
199 """Populates a module.Struct based on a MojomStruct. | |
200 | |
201 Args: | |
202 struct: {module.Struct} to be populated. | |
203 mojom_struct: {mojom_types.MojomStruct} to be translated. | |
204 """ | |
205 self.PopulateUserDefinedType(struct, mojom_struct) | |
206 # mojom_struct.fields is indexed by the field ordinals. | |
207 struct.fields_in_ordinal_order = [self.StructFieldFromMojom(ordinal, f) | |
208 for (ordinal, f) in enumerate(mojom_struct.fields)] | |
209 # We also want a list of fields sorted in declaration_order. | |
210 struct.fields = [f for f in struct.fields_in_ordinal_order] | |
211 struct.fields.sort(key=lambda field: field.declaration_order) | |
212 | |
213 assert mojom_struct.version_info | |
214 struct.versions = [self.VersionInfoFromMojom(version) for version in | |
215 mojom_struct.version_info] | |
216 self.PopulateContainedDeclarationsFromMojom( | |
217 struct, mojom_struct.decl_data.contained_declarations) | |
218 | |
219 def UnionFieldFromMojom(self, mojom_field): | |
220 """Translates a mojom_types_mojom.UnionField to a module.UnionField. | |
221 | |
222 Args: | |
223 mojom_field: {mojom_types_mojom.UnionField} to be translated. | |
224 | |
225 Returns: | |
226 {module.UnionField} translated from mojom_field. | |
227 """ | |
228 union_field = module.UnionField() | |
229 self.PopulateCommonFieldValues(union_field, mojom_field) | |
230 # The |ordinal| attribute of |union_field| contains the field's tag | |
231 # as computed by the Mojom front-end. | |
232 union_field.ordinal = mojom_field.tag | |
233 # The |declared_tag| field is populated only if the user explicitly | |
234 # specified a tag for the field in the .mojom file and as such is not | |
235 # defined for every field. If defined it is equal to the |ordinal| | |
236 # attribute. Currently no code generators are consuming this data. | |
237 union_field.declared_tag = self.OrdinalFromMojom(mojom_field) | |
238 # The declaration_order field preserves the index of the field in | |
239 # declaration order in the .mojom file. | |
240 union_field.declaration_order = mojom_field.decl_data.declaration_order | |
241 return union_field | |
242 | |
243 def StructFieldFromMojom(self, ordinal, mojom_field): | |
244 """Translates a mojom_types_mojom.StructField to a module.StructField. | |
245 | |
246 Args: | |
247 ordinal: {int} The 0-based ordinal position of the field within the | |
248 struct. Note that this is not necessarily the same as the lexical | |
249 order or the packing order. | |
250 mojom_field: {mojom_types_mojom.StructField} to be translated. | |
251 | |
252 Returns: | |
253 {module.StructField} translated from mojom_field. | |
254 """ | |
255 struct_field = module.StructField() | |
256 self.PopulateCommonFieldValues(struct_field, mojom_field) | |
257 struct_field.computed_offset = mojom_field.offset | |
258 struct_field.computed_bit = mojom_field.bit | |
259 struct_field.computed_min_version = mojom_field.min_version | |
260 # Note that the |ordinal| attribute of |struct_field| records only the | |
261 # *declared* ordinal and as such is not defined for every field whereas | |
262 # the |computed_ordinal| attribute is defined for every field. If | |
263 # |ordinal| is defined then it is equal to |computed_ordinal|. | |
264 struct_field.ordinal = self.OrdinalFromMojom(mojom_field) | |
265 struct_field.computed_ordinal = ordinal | |
266 struct_field.declaration_order = mojom_field.decl_data.declaration_order | |
267 if mojom_field.default_value: | |
268 if (mojom_field.default_value.tag == | |
269 mojom_types_mojom.DefaultFieldValue.Tags.default_keyword): | |
270 struct_field.default = 'default' | |
271 else: | |
272 struct_field.default = self.ValueFromMojom( | |
273 mojom_field.default_value.value) | |
274 | |
275 return struct_field | |
276 | |
277 def VersionInfoFromMojom(self, mojom_version): | |
278 """Translates a mojom_types_mojom.StructVersion to a pack.VersionInfo | |
279 Args: | |
280 mojom_version: {mojom_types_mojom.StructVersion} to be translated. | |
281 | |
282 Returns: | |
283 {pack.VersionInfo} translated from |mojom_version|. | |
284 """ | |
285 return pack.VersionInfo(mojom_version.version_number, | |
286 mojom_version.num_fields, mojom_version.num_bytes) | |
287 | |
288 | |
289 def ParamFromMojom(self, mojom): | |
290 """Translates a mojom_types_mojom.StructField to a module.Parameter. | |
291 | |
292 The parameters passed to and returned from a method are expressed as a | |
293 struct. The struct fields in the struct are the parameters. | |
294 | |
295 Args: | |
296 mojom: {mojom_types_mojom.StructField} representing a method parameter. | |
297 | |
298 Returns: | |
299 {module.Parameter} translated from the mojom. | |
300 """ | |
301 param = module.Parameter() | |
302 param.ordinal = self.OrdinalFromMojom(mojom) | |
303 self.PopulateCommonFieldValues(param, mojom) | |
304 return param | |
305 | |
306 def PopulateCommonFieldValues(self, field, mojom_field): | |
307 """Populates a number of common field values based on a mojom field. | |
308 | |
309 Args: | |
310 field: {module.Field|module.Parameter} to be populated. | |
311 mojom_field: {StructField|UnionField} to be translated. | |
312 """ | |
313 # TODO(rudominer) Some of the code generators check that the type | |
314 # of field.name is a non-unicode string. If we change this we can | |
315 # remove the str() below. | |
316 field.name = str(mojom_field.decl_data.short_name) | |
317 field.kind = self.KindFromMojom(mojom_field.type) | |
318 field.attributes = self.AttributesFromMojom(mojom_field) | |
319 | |
320 def PopulateContainedDeclarationsFromMojom( | |
321 self, parent_kind, contained_declarations): | |
322 """Populates a module.Struct|module.Interface with contained declarations. | |
323 | |
324 Args: | |
325 parent_kind: {module.Struct|module.Interface} to be populated. | |
326 contained_declarations: {mojom_types_mojom.ContainedDeclarations} from | |
327 which the contained types need to be extracted. | |
328 """ | |
329 if not contained_declarations: | |
330 return | |
331 | |
332 if contained_declarations.enums: | |
333 for enum_key in contained_declarations.enums: | |
334 enum = self.UserDefinedFromTypeKey(enum_key) | |
335 parent_kind.enums.append(enum) | |
336 | |
337 if contained_declarations.constants: | |
338 for const_key in contained_declarations.constants: | |
339 const = self.ConstantFromKey(const_key) | |
340 parent_kind.constants.append(const) | |
341 | |
342 def EnumFromMojom(self, enum, mojom_type): | |
343 """Populates a module.Enum based on a MojomEnum. | |
344 | |
345 Args: | |
346 enum: {module.Enum} to be populated. | |
347 mojom_type: {mojom_types_mojom.Type} referring to the MojomEnum to be | |
348 translated. | |
349 """ | |
350 assert mojom_type.tag == mojom_types_mojom.UserDefinedType.Tags.enum_type | |
351 mojom_enum = mojom_type.enum_type | |
352 self.PopulateUserDefinedType(enum, mojom_enum) | |
353 if mojom_enum.decl_data.container_type_key: | |
354 parent_kind = self.UserDefinedFromTypeKey( | |
355 mojom_enum.decl_data.container_type_key) | |
356 enum.parent_kind = parent_kind | |
357 enum.fields = [self.EnumFieldFromMojom(value) | |
358 for value in mojom_enum.values] | |
359 | |
360 def EnumFieldFromMojom(self, mojom_enum_value): | |
361 """Translates an mojom_types_mojom.EnumValue to a module.EnumField. | |
362 | |
363 mojom_enum_value: {mojom_types_mojom.EnumValue} to be translated. | |
364 | |
365 Returns: | |
366 {module.EnumField} translated from mojom_enum_value. | |
367 """ | |
368 field = module.EnumField() | |
369 field.name = mojom_enum_value.decl_data.short_name | |
370 field.attributes = self.AttributesFromMojom(mojom_enum_value) | |
371 field.numeric_value = mojom_enum_value.int_value | |
372 if mojom_enum_value.initializer_value is not None: | |
373 field.value = self.ValueFromMojom(mojom_enum_value.initializer_value) | |
374 | |
375 return field | |
376 | |
377 def AttributesFromMojom(self, mojom): | |
378 """Extracts the attributes from a Mojom object into a dict. | |
379 | |
380 Args: | |
381 mojom: A type in mojom_types_mojom containing a decl_data field. | |
382 | |
383 Returns: | |
384 {dict<str, str>} of the attributes. | |
385 """ | |
386 if not mojom.decl_data.attributes: | |
387 return None | |
388 | |
389 # Note that attribute values are typed. That is why we use | |
390 # attr.value.data directly instead of the string representation of it. | |
391 return {attr.key: attr.value.data for attr in mojom.decl_data.attributes} | |
392 | |
393 def PopulateUserDefinedType(self, module_type, mojom): | |
394 """Populates fields that are common among user-defined types. | |
395 | |
396 Args: | |
397 module_type: {module.Struct|Union|Enum} to be populated. | |
398 mojom: {MojomStruct|MojomUnion|MojomEnum} to be translated. | |
399 """ | |
400 module_type.attributes = self.AttributesFromMojom(mojom) | |
401 module_type.name = mojom.decl_data.short_name | |
402 module_type.spec = mojom.decl_data.full_identifier | |
403 if module_type.spec == None: | |
404 module_type.spec = mojom.decl_data.short_name | |
405 self.PopulateModuleOrImportedFrom(module_type, mojom) | |
406 | |
407 def PopulateModuleOrImportedFrom(self, module_type, mojom): | |
408 """Populates either the module field or the imported_from field. | |
409 | |
410 All user-defined types must have either the module field populated (if | |
411 they are from the currently-processed module) or the imported_from (if | |
412 they are imported from another module). | |
413 | |
414 Args: | |
415 module_type: {module.Struct|Union|Enum|Interface} to be populated. | |
416 mojom: {MojomStruct|MojomUnion|MojomEnum|MojomInterface} to be translated. | |
417 """ | |
418 if mojom.decl_data.source_file_info: | |
419 if mojom.decl_data.source_file_info.file_name == self._file_name: | |
420 module_type.module = self._module | |
421 else: | |
422 imported_from = self._transitive_imports[ | |
423 mojom.decl_data.source_file_info.file_name] | |
424 module_type.imported_from = imported_from | |
425 module_type.module = imported_from['module'] | |
426 | |
427 | |
428 def OrdinalFromMojom(self, mojom): | |
429 """Extracts the declared ordinal from a mojom StructField or UnionField. | |
430 | |
431 Args: | |
432 mojom: {MojomStruct|MojomUnion} from which the ordinal is to be extracted. | |
433 | |
434 Returns: | |
435 {int} if an ordinal was present, {NoneType} otherwise. | |
436 """ | |
437 ordinal = mojom.decl_data.declared_ordinal | |
438 if ordinal < 0: | |
439 return None | |
440 return ordinal | |
441 | |
442 def InterfaceFromMojom(self, interface, mojom_type): | |
443 """Populates a module.Interface from a mojom_types_mojom.MojomInterface. | |
444 | |
445 Args: | |
446 interface: {module.Interface} to be populated. | |
447 mojom_type: {UserDefinedType} referring to the MojomInterface to be | |
448 translated. | |
449 """ | |
450 assert (mojom_type.tag | |
451 == mojom_types_mojom.UserDefinedType.Tags.interface_type) | |
452 mojom_interface = mojom_type.interface_type | |
453 interface.attributes = self.AttributesFromMojom(mojom_interface) | |
454 self.PopulateModuleOrImportedFrom(interface, mojom_interface) | |
455 interface.name = mojom_interface.decl_data.short_name | |
456 interface.spec = interface.name | |
457 interface.version = mojom_interface.current_version | |
458 interface.service_name = mojom_interface.service_name | |
459 if interface.attributes: | |
460 assert interface.service_name == interface.attributes.get( | |
461 'ServiceName', None), interface.service_name | |
462 else: | |
463 assert interface.service_name is None, interface.service_name | |
464 | |
465 | |
466 # Translate the dictionary of methods into a list of module.Methods. | |
467 interface.methods = [self.MethodFromMojom(mojom_method, interface) | |
468 for ordinal, mojom_method in mojom_interface.methods.iteritems()] | |
469 # We want the methods in an interface to be in some deterministic order | |
470 # and we choose declaration order (i.e. lexical order within the | |
471 # .mojom file.) | |
472 interface.methods.sort(key=lambda method: method.declaration_order) | |
473 self.PopulateContainedDeclarationsFromMojom( | |
474 interface, mojom_interface.decl_data.contained_declarations) | |
475 | |
476 def MethodFromMojom(self, mojom_method, interface): | |
477 """Translates a mojom_types_mojom.MojomMethod to a module.Method. | |
478 | |
479 Args: | |
480 mojom_method: {mojom_types_mojom.MojomMethod} to be translated. | |
481 interface: {module.Interface} the method is a member of. | |
482 | |
483 Returns: | |
484 {module.Method} translated from mojom_method. | |
485 """ | |
486 method = module.Method(interface, mojom_method.decl_data.short_name) | |
487 method.ordinal = mojom_method.ordinal | |
488 method.declaration_order = mojom_method.decl_data.declaration_order | |
489 method.param_struct = module.Struct() | |
490 self.StructFromMojomStruct(method.param_struct, mojom_method.parameters) | |
491 # The name of a synthetic request parameter struct is not guaranteed by | |
492 # the frontend to be anything in particular so we set the name of the | |
493 # translated struct to a value that the code generators are expecting. | |
494 method.param_struct.name = "%s_%s_Params" % ( | |
495 method.interface.name, method.name) | |
496 method.parameters = [self.ParamFromMojom(param) | |
497 for param in mojom_method.parameters.fields] | |
498 if mojom_method.response_params is not None: | |
499 method.response_param_struct = module.Struct() | |
500 self.StructFromMojomStruct(method.response_param_struct, | |
501 mojom_method.response_params) | |
502 # The name of a synthetic response parameter struct is not guaranteed by | |
503 # the frontend to be anything in particular so we set the name of the | |
504 # translated struct to a value that the code generators are expecting. | |
505 method.response_param_struct.name = "%s_%s_ResponseParams" % ( | |
506 method.interface.name, method.name) | |
507 method.response_parameters = [self.ParamFromMojom(param) | |
508 for param in mojom_method.response_params.fields] | |
509 | |
510 method.min_version=mojom_method.min_version | |
511 | |
512 return method | |
513 | |
514 def ConstantFromKey(self, constant_key): | |
515 """Takes a key into the map graph.resolved_constants and returns the module | |
516 equivalent constant. | |
517 | |
518 Args: | |
519 constant_key: {str} the key referring to the constant whose translation | |
520 is to be returned. | |
521 | |
522 Returns: | |
523 {module.Constant} translated. | |
524 """ | |
525 if constant_key in self._constant_cache: | |
526 return self._constant_cache[constant_key] | |
527 | |
528 mojom_const = self._graph.resolved_constants[constant_key] | |
529 const = module.Constant() | |
530 self._constant_cache[constant_key] = const | |
531 | |
532 self.ConstantFromMojom(const, mojom_const) | |
533 return const | |
534 | |
535 def ConstantFromMojom(self, const, mojom_const): | |
536 """Populates a module.Constant based on a DeclaredConstant. | |
537 | |
538 Args: | |
539 const: {module.Constant} to be populated. | |
540 mojom_const: {mojom_types_mojom.DeclaredConstant} to be translated. | |
541 | |
542 Returns: | |
543 {module.Constant} translated from mojom_const. | |
544 """ | |
545 const.name = mojom_const.decl_data.short_name | |
546 const.kind = self.KindFromMojom(mojom_const.type) | |
547 const.value = self.ValueFromMojom(mojom_const.value) | |
548 const.parent_kind = None | |
549 if mojom_const.decl_data.container_type_key: | |
550 const.parent_kind = self.UserDefinedFromTypeKey( | |
551 mojom_const.decl_data.container_type_key) | |
552 | |
553 def ValueFromMojom(self, value): | |
554 """Translates a mojom_types_mojom.Value. | |
555 | |
556 Args: | |
557 value: {mojom_types_mojom.Value} to be translated. | |
558 | |
559 Returns: | |
560 {str|module.BuiltinValue|module.NamedValue} translated from the passed in | |
561 mojom_value. | |
562 If value is a literal value, a string is returned. If the literal value is | |
563 a string literal value, the returned string is enclosed in double | |
564 quotes. If the literal value is a boolean literal value then one of the | |
565 strings 'true' or 'false' is returned. Otherwise the literal value is a | |
566 numeric literal value and in this case the returned value is a Python | |
567 string representation of the numeric value. | |
568 If value is a built-in value, a module.BuiltinValue is returned. | |
569 If value is a user defined reference, a module.NamedValue is returned. | |
570 """ | |
571 if value.tag == mojom_types_mojom.Value.Tags.literal_value: | |
572 if (value.literal_value.tag | |
573 == mojom_types_mojom.LiteralValue.Tags.string_value): | |
574 return '"%s"' % value.literal_value.data | |
575 if (value.literal_value.tag | |
576 == mojom_types_mojom.LiteralValue.Tags.bool_value): | |
577 # The strings 'true' and 'false' are used to represent bool literals. | |
578 return ('%s' % value.literal_value.data).lower() | |
579 elif (value.literal_value.tag | |
580 == mojom_types_mojom.LiteralValue.Tags.float_value or | |
581 value.literal_value.tag | |
582 == mojom_types_mojom.LiteralValue.Tags.double_value): | |
583 # Use the Python repr() function to get a string that accurately | |
584 # represents the value of the floating point number. | |
585 return repr(value.literal_value.data) | |
586 return str(value.literal_value.data) | |
587 elif value.tag == mojom_types_mojom.Value.Tags.builtin_value: | |
588 mojom_to_builtin = { | |
589 mojom_types_mojom.BuiltinConstantValue.DOUBLE_INFINITY: | |
590 'double.INFINITY', | |
591 mojom_types_mojom.BuiltinConstantValue.DOUBLE_NEGATIVE_INFINITY: | |
592 'double.NEGATIVE_INFINITY', | |
593 mojom_types_mojom.BuiltinConstantValue.DOUBLE_NAN: | |
594 'double.NAN', | |
595 mojom_types_mojom.BuiltinConstantValue.FLOAT_INFINITY: | |
596 'float.INFINITY', | |
597 mojom_types_mojom.BuiltinConstantValue.FLOAT_NEGATIVE_INFINITY: | |
598 'float.NEGATIVE_INFINITY', | |
599 mojom_types_mojom.BuiltinConstantValue.FLOAT_NAN: 'float.NAN', | |
600 } | |
601 return module.BuiltinValue(mojom_to_builtin[value.builtin_value]) | |
602 return self.FromUserValueReference(value) | |
603 | |
604 def FromUserValueReference(self, value): | |
605 """Translates a mojom_types.EnumValueReference or ConstantReference into the | |
606 module equivalent. | |
607 | |
608 Args: | |
609 value: {mojom_types_mojom.Value} the value ref to be translated. It | |
610 must be of type EnumValueReference or ConstantReference. | |
611 | |
612 Returns: | |
613 {module.EnumValue|module.ConstantValue} translated. | |
614 """ | |
615 if value.tag == mojom_types_mojom.Value.Tags.constant_reference: | |
616 return self.ConstantValueFromKey(value.constant_reference.constant_key) | |
617 assert value.tag == mojom_types_mojom.Value.Tags.enum_value_reference | |
618 return self.EnumValueFromKey(value.enum_value_reference.enum_type_key, | |
619 value.enum_value_reference.enum_value_index) | |
620 | |
621 def ConstantValueFromKey(self, constant_key): | |
622 """Takes a key into graph.resolved_constants referring to a | |
623 mojom declared_constant and returns a module.ConstantValue referring to the | |
624 module equivalent constant. | |
625 | |
626 Args: | |
627 constant_key: {str} the constant key referring to a constant. | |
628 | |
629 Returns: | |
630 {module.ConstantValue} translated. | |
631 """ | |
632 if constant_key in self._value_cache: | |
633 return self._value_cache[constant_key] | |
634 | |
635 const_value = module.ConstantValue() | |
636 self._value_cache[constant_key] = const_value | |
637 | |
638 const = self.ConstantFromKey(constant_key) | |
639 const_value.constant = const | |
640 const_value.name = const.name | |
641 const_value.parent_kind = const.parent_kind | |
642 self.PopulateModuleOrImportedFrom(const_value, | |
643 self._graph.resolved_constants[constant_key]) | |
644 const_value.namespace = const_value.module.namespace | |
645 return const_value | |
646 | |
647 def EnumValueFromKey(self, enum_type_key, enum_value_index): | |
648 """Takes an enum type key and an enum value index (together these | |
649 form a key to a mojom_enum_value) and returns a module.EnumValue referring | |
650 the module equivalent enum value | |
651 | |
652 Args: | |
653 enum_type_key: {str} the type key of a mojom_enum | |
654 enum_value_index: {int} the 0-based index into the |values| array of | |
655 the mojom_enum | |
656 | |
657 Returns: | |
658 {module.EnumValue} translated from mojom_enum_value. | |
659 """ | |
660 enum_value_key = (enum_type_key, enum_value_index) | |
661 if enum_value_key in self._value_cache: | |
662 return self._value_cache[enum_value_key] | |
663 | |
664 mojom_enum = self._graph.resolved_types[enum_type_key].enum_type | |
665 mojom_enum_value = mojom_enum.values[enum_value_index] | |
666 | |
667 # We need to create and cache the EnumValue object just in case later calls | |
668 # require the creation of that same EnumValue object. | |
669 enum_value = module.EnumValue() | |
670 self._value_cache[enum_value_key] = enum_value | |
671 | |
672 enum = self.UserDefinedFromTypeKey(enum_type_key) | |
673 enum_value.enum = enum | |
674 self.PopulateModuleOrImportedFrom(enum_value, mojom_enum_value) | |
675 enum_value.namespace = enum_value.module.namespace | |
676 enum_value.parent_kind = enum.parent_kind | |
677 enum_value.name = mojom_enum_value.decl_data.short_name | |
678 | |
679 return enum_value | |
680 | |
681 def KindFromMojom(self, mojom_type): | |
682 """Translates a mojom_types_mojom.Type to its equivalent module type. | |
683 | |
684 It is guaranteed that two calls to KindFromMojom with the same input yield | |
685 the same object. | |
686 | |
687 Args: | |
688 mojom_type: {mojom_types_mojom.Type} to be translated. | |
689 | |
690 Returns: | |
691 {module.Kind} translated from mojom_type. | |
692 """ | |
693 mappers = { | |
694 mojom_types_mojom.Type.Tags.simple_type: self.SimpleKindFromMojom, | |
695 mojom_types_mojom.Type.Tags.string_type: self.StringFromMojom, | |
696 mojom_types_mojom.Type.Tags.handle_type: self.HandleFromMojom, | |
697 mojom_types_mojom.Type.Tags.array_type: self.ArrayFromMojom, | |
698 mojom_types_mojom.Type.Tags.map_type: self.MapFromMojom, | |
699 mojom_types_mojom.Type.Tags.type_reference: self.UserDefinedFromTypeRef, | |
700 } | |
701 return mappers[mojom_type.tag](mojom_type) | |
702 | |
703 def SimpleKindFromMojom(self, mojom_type): | |
704 """Translates a simple type to its module equivalent. | |
705 | |
706 Args: | |
707 mojom_type: {mojom_types_mojom.Type} with its simple_type field set to be | |
708 translated. | |
709 | |
710 Returns: | |
711 {module.Kind} translated from mojom_type. | |
712 """ | |
713 simple_mojom_types = { | |
714 mojom_types_mojom.SimpleType.BOOL: module.BOOL, | |
715 mojom_types_mojom.SimpleType.INT8: module.INT8, | |
716 mojom_types_mojom.SimpleType.INT16: module.INT16, | |
717 mojom_types_mojom.SimpleType.INT32: module.INT32, | |
718 mojom_types_mojom.SimpleType.INT64: module.INT64, | |
719 mojom_types_mojom.SimpleType.UINT8: module.UINT8, | |
720 mojom_types_mojom.SimpleType.UINT16: module.UINT16, | |
721 mojom_types_mojom.SimpleType.UINT32: module.UINT32, | |
722 mojom_types_mojom.SimpleType.UINT64: module.UINT64, | |
723 mojom_types_mojom.SimpleType.FLOAT: module.FLOAT, | |
724 mojom_types_mojom.SimpleType.DOUBLE: module.DOUBLE, | |
725 } | |
726 return simple_mojom_types[mojom_type.simple_type] | |
727 | |
728 def HandleFromMojom(self, mojom_type): | |
729 """Translates a handle type to its module equivalent. | |
730 | |
731 Args: | |
732 mojom_type: {mojom_types_mojom.Type} with its handle_type field set to be | |
733 translated. | |
734 | |
735 Returns: | |
736 {module.ReferenceKind} translated from mojom_type. | |
737 """ | |
738 handle_mojom_types = { | |
739 mojom_types_mojom.HandleType.Kind.UNSPECIFIED: module.HANDLE, | |
740 mojom_types_mojom.HandleType.Kind.MESSAGE_PIPE: module.MSGPIPE, | |
741 mojom_types_mojom.HandleType.Kind.DATA_PIPE_CONSUMER: module.DCPIPE, | |
742 mojom_types_mojom.HandleType.Kind.DATA_PIPE_PRODUCER: module.DPPIPE, | |
743 mojom_types_mojom.HandleType.Kind.SHARED_BUFFER: module.SHAREDBUFFER, | |
744 } | |
745 | |
746 nullable_handle_mojom_types = { | |
747 mojom_types_mojom.HandleType.Kind.UNSPECIFIED: module.NULLABLE_HANDLE, | |
748 mojom_types_mojom.HandleType.Kind.MESSAGE_PIPE: module.NULLABLE_MSGPIPE, | |
749 mojom_types_mojom.HandleType.Kind.DATA_PIPE_CONSUMER: | |
750 module.NULLABLE_DCPIPE, | |
751 mojom_types_mojom.HandleType.Kind.DATA_PIPE_PRODUCER: | |
752 module.NULLABLE_DPPIPE, | |
753 mojom_types_mojom.HandleType.Kind.SHARED_BUFFER: | |
754 module.NULLABLE_SHAREDBUFFER, | |
755 } | |
756 | |
757 if mojom_type.handle_type.nullable: | |
758 return nullable_handle_mojom_types[mojom_type.handle_type.kind] | |
759 return handle_mojom_types[mojom_type.handle_type.kind] | |
760 | |
761 def StringFromMojom(self, mojom_type): | |
762 """Translates a string type to its module equivalent. | |
763 | |
764 Args: | |
765 mojom_type: {mojom_types_mojom.Type} with its string_type field set to be | |
766 translated. | |
767 | |
768 Returns: | |
769 {module.ReferenceKind} translated from mojom_type. Either module.STRING or | |
770 module.NULLABLE_STRING. | |
771 """ | |
772 if mojom_type.string_type.nullable: | |
773 return module.NULLABLE_STRING | |
774 return module.STRING | |
775 | |
776 def ArrayFromMojom(self, mojom_type): | |
777 """Translates an array type to its module equivalent. | |
778 | |
779 Args: | |
780 mojom_type: {mojom_types_mojom.Type} with its array_type field set to be | |
781 translated. | |
782 | |
783 Returns: | |
784 {module.Array} translated from mojom_type. | |
785 """ | |
786 array = module.Array( | |
787 kind=self.KindFromMojom(mojom_type.array_type.element_type)) | |
788 if mojom_type.array_type.fixed_length > 0: | |
789 array.length = mojom_type.array_type.fixed_length | |
790 if mojom_type.array_type.nullable: | |
791 return array.MakeNullableKind() | |
792 return array | |
793 | |
794 def MapFromMojom(self, mojom_type): | |
795 """Translates a map type to its module equivalent. | |
796 | |
797 Args: | |
798 mojom_type: {mojom_types_mojom.Type} with its map_type field set to be | |
799 translated. | |
800 | |
801 Returns: | |
802 {module.Map} translated from mojom_type. | |
803 """ | |
804 key_kind = self.KindFromMojom(mojom_type.map_type.key_type) | |
805 value_kind = self.KindFromMojom(mojom_type.map_type.value_type) | |
806 module_map = module.Map(key_kind=key_kind, value_kind=value_kind) | |
807 if mojom_type.map_type.nullable: | |
808 return module_map.MakeNullableKind() | |
809 return module_map | |
810 | |
811 def UserDefinedFromTypeRef(self, mojom_type): | |
812 """Translates a type reference to the module equivalent of the | |
813 UserDefinedType that the reference refers to. | |
814 | |
815 Args: | |
816 mojom_type: {mojom_types_mojom.Type} with its type_reference field set to | |
817 be translated. | |
818 | |
819 Returns: | |
820 {module.Enum|Struct|Union|Interface} translated from mojom_type. | |
821 """ | |
822 type_key = mojom_type.type_reference.type_key | |
823 module_type = self.UserDefinedFromTypeKey(type_key) | |
824 if mojom_type.type_reference.is_interface_request: | |
825 module_type = module.InterfaceRequest(module_type) | |
826 if mojom_type.type_reference.nullable: | |
827 return module_type.MakeNullableKind() | |
828 return module_type | |
829 | |
830 def UserDefinedFromTypeKey(self, type_key): | |
831 """Takes a type key into graph.resolved_types and returns the module | |
832 equivalent. | |
833 | |
834 Args: | |
835 type_key: {str} the type key referring to the type to be returned. | |
836 | |
837 Returns: | |
838 {module.Enum|Struct|Union|Interface} translated. | |
839 """ | |
840 if type_key in self._type_cache: | |
841 return self._type_cache[type_key] | |
842 else: | |
843 mojom_type = self._graph.resolved_types[type_key] | |
844 return self.UserDefinedFromMojom(type_key, mojom_type) | |
845 | |
846 def UserDefinedFromMojom(self, type_key, mojom_type): | |
847 """Translates a user defined type to its module equivalent. | |
848 | |
849 Args: | |
850 type_key: {str} the type key referring to the type in graph.resolved_types | |
851 used to cache the type object. | |
852 mojom_type: {mojom_types_mojom.UserDefinedType} to be translated. | |
853 | |
854 Returns: | |
855 {module.Enum|Struct|Union|Interface} translated from mojom_type. | |
856 """ | |
857 user_defined_types = { | |
858 mojom_types_mojom.UserDefinedType.Tags.struct_type: | |
859 (module.Struct, self.StructFromMojom), | |
860 mojom_types_mojom.UserDefinedType.Tags.enum_type: | |
861 (module.Enum, self.EnumFromMojom), | |
862 mojom_types_mojom.UserDefinedType.Tags.union_type: | |
863 (module.Union, self.UnionFromMojom), | |
864 mojom_types_mojom.UserDefinedType.Tags.interface_type: | |
865 (module.Interface, self.InterfaceFromMojom), | |
866 } | |
867 module_type_class, from_mojom = user_defined_types[mojom_type.tag] | |
868 module_type = module_type_class() | |
869 | |
870 if module_type.spec == None: | |
871 # module.py expects the spec of user defined types to be set when | |
872 # constructing map, array, and interface request types, but the value | |
873 # appears to be only used for error messages. | |
874 module_type.spec = 'dummyspec' | |
875 | |
876 # It is necessary to cache the type object before populating it since in | |
877 # the course of populating it, it may be necessary to resolve that same | |
878 # type (say, a struct with a field of its own type). | |
879 self._type_cache[type_key] = module_type | |
880 from_mojom(module_type, mojom_type) | |
881 | |
882 module_type.type_key = type_key | |
883 | |
884 return module_type | |
885 | |
886 | |
887 def TranslateFileGraph(graph): | |
888 """Translates a mojom_types_mojom.MojomFileGraph to module.Module(s). | |
889 | |
890 The input is the output of the parser. The output is the input to the | |
891 various bindings generators. | |
892 | |
893 Args: | |
894 graph: {mojom_types_mojom.MojomFileGraph} to be translated. | |
895 | |
896 Return: | |
897 {dict<str, module.Module>} mapping the file's name to its module.Module | |
898 translation for all files in graph.files. | |
899 """ | |
900 return {file_name: FileTranslator(graph, file_name).Translate() | |
901 for file_name in graph.files} | |
OLD | NEW |