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

Side by Side Diff: mojo/public/tools/bindings/pylib/mojom/generate/data.py

Issue 814543006: Move //mojo/{public, edk} underneath //third_party (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 11 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 unified diff | Download patch
OLDNEW
(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 # TODO(vtl): "data" is a pretty vague name. Rename it?
6
7 import copy
8
9 import module as mojom
10
11 # This module provides a mechanism to turn mojom Modules to dictionaries and
12 # back again. This can be used to persist a mojom Module created progromatically
13 # or to read a dictionary from code or a file.
14 # Example:
15 # test_dict = {
16 # 'name': 'test',
17 # 'namespace': 'testspace',
18 # 'structs': [{
19 # 'name': 'teststruct',
20 # 'fields': [
21 # {'name': 'testfield1', 'kind': 'i32'},
22 # {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}],
23 # 'interfaces': [{
24 # 'name': 'Server',
25 # 'methods': [{
26 # 'name': 'Foo',
27 # 'parameters': [{
28 # 'name': 'foo', 'kind': 'i32'},
29 # {'name': 'bar', 'kind': 'a:x:teststruct'}],
30 # 'ordinal': 42}]}]
31 # }
32 # test_module = data.ModuleFromData(test_dict)
33
34 # Used to create a subclass of str that supports sorting by index, to make
35 # pretty printing maintain the order.
36 def istr(index, string):
37 class IndexedString(str):
38 def __lt__(self, other):
39 return self.__index__ < other.__index__
40
41 rv = IndexedString(string)
42 rv.__index__ = index
43 return rv
44
45 builtin_values = frozenset([
46 "double.INFINITY",
47 "double.NEGATIVE_INFINITY",
48 "double.NAN",
49 "float.INFINITY",
50 "float.NEGATIVE_INFINITY",
51 "float.NAN"])
52
53 def IsBuiltinValue(value):
54 return value in builtin_values
55
56 def LookupKind(kinds, spec, scope):
57 """Tries to find which Kind a spec refers to, given the scope in which its
58 referenced. Starts checking from the narrowest scope to most general. For
59 example, given a struct field like
60 Foo.Bar x;
61 Foo.Bar could refer to the type 'Bar' in the 'Foo' namespace, or an inner
62 type 'Bar' in the struct 'Foo' in the current namespace.
63
64 |scope| is a tuple that looks like (namespace, struct/interface), referring
65 to the location where the type is referenced."""
66 if spec.startswith('x:'):
67 name = spec[2:]
68 for i in xrange(len(scope), -1, -1):
69 test_spec = 'x:'
70 if i > 0:
71 test_spec += '.'.join(scope[:i]) + '.'
72 test_spec += name
73 kind = kinds.get(test_spec)
74 if kind:
75 return kind
76
77 return kinds.get(spec)
78
79 def LookupValue(values, name, scope, kind):
80 """Like LookupKind, but for constant values."""
81 # If the type is an enum, the value can be specified as a qualified name, in
82 # which case the form EnumName.ENUM_VALUE must be used. We use the presence
83 # of a '.' in the requested name to identify this. Otherwise, we prepend the
84 # enum name.
85 if isinstance(kind, mojom.Enum) and '.' not in name:
86 name = '%s.%s' % (kind.spec.split(':', 1)[1], name)
87 for i in reversed(xrange(len(scope) + 1)):
88 test_spec = '.'.join(scope[:i])
89 if test_spec:
90 test_spec += '.'
91 test_spec += name
92 value = values.get(test_spec)
93 if value:
94 return value
95
96 return values.get(name)
97
98 def FixupExpression(module, value, scope, kind):
99 """Translates an IDENTIFIER into a built-in value or structured NamedValue
100 object."""
101 if isinstance(value, tuple) and value[0] == 'IDENTIFIER':
102 # Allow user defined values to shadow builtins.
103 result = LookupValue(module.values, value[1], scope, kind)
104 if result:
105 if isinstance(result, tuple):
106 raise Exception('Unable to resolve expression: %r' % value[1])
107 return result
108 if IsBuiltinValue(value[1]):
109 return mojom.BuiltinValue(value[1])
110 return value
111
112 def KindToData(kind):
113 return kind.spec
114
115 def KindFromData(kinds, data, scope):
116 kind = LookupKind(kinds, data, scope)
117 if kind:
118 return kind
119
120 if data.startswith('?'):
121 kind = KindFromData(kinds, data[1:], scope).MakeNullableKind()
122 elif data.startswith('a:'):
123 kind = mojom.Array(KindFromData(kinds, data[2:], scope))
124 elif data.startswith('a'):
125 colon = data.find(':')
126 length = int(data[1:colon])
127 kind = mojom.Array(KindFromData(kinds, data[colon+1:], scope), length)
128 elif data.startswith('r:'):
129 kind = mojom.InterfaceRequest(KindFromData(kinds, data[2:], scope))
130 elif data.startswith('m['):
131 # Isolate the two types from their brackets.
132
133 # It is not allowed to use map as key, so there shouldn't be nested ']'s
134 # inside the key type spec.
135 key_end = data.find(']')
136 assert key_end != -1 and key_end < len(data) - 1
137 assert data[key_end+1] == '[' and data[-1] == ']'
138
139 first_kind = data[2:key_end]
140 second_kind = data[key_end+2:-1]
141
142 kind = mojom.Map(KindFromData(kinds, first_kind, scope),
143 KindFromData(kinds, second_kind, scope))
144 else:
145 kind = mojom.Kind(data)
146
147 kinds[data] = kind
148 return kind
149
150 def KindFromImport(original_kind, imported_from):
151 """Used with 'import module' - clones the kind imported from the given
152 module's namespace. Only used with Structs, Unions, Interfaces and Enums."""
153 kind = copy.copy(original_kind)
154 # |shared_definition| is used to store various properties (see
155 # |AddSharedProperty()| in module.py), including |imported_from|. We don't
156 # want the copy to share these with the original, so copy it if necessary.
157 if hasattr(original_kind, 'shared_definition'):
158 kind.shared_definition = copy.copy(original_kind.shared_definition)
159 kind.imported_from = imported_from
160 return kind
161
162 def ImportFromData(module, data):
163 import_module = data['module']
164
165 import_item = {}
166 import_item['module_name'] = import_module.name
167 import_item['namespace'] = import_module.namespace
168 import_item['module'] = import_module
169
170 # Copy the struct kinds from our imports into the current module.
171 importable_kinds = (mojom.Struct, mojom.Union, mojom.Enum, mojom.Interface)
172 for kind in import_module.kinds.itervalues():
173 if (isinstance(kind, importable_kinds) and
174 kind.imported_from is None):
175 kind = KindFromImport(kind, import_item)
176 module.kinds[kind.spec] = kind
177 # Ditto for values.
178 for value in import_module.values.itervalues():
179 if value.imported_from is None:
180 # Values don't have shared definitions (since they're not nullable), so no
181 # need to do anything special.
182 value = copy.copy(value)
183 value.imported_from = import_item
184 module.values[value.GetSpec()] = value
185
186 return import_item
187
188 def StructToData(struct):
189 return {
190 istr(0, 'name'): struct.name,
191 istr(1, 'fields'): map(FieldToData, struct.fields)
192 }
193
194 def StructFromData(module, data):
195 struct = mojom.Struct(module=module)
196 struct.name = data['name']
197 struct.attributes = data['attributes']
198 struct.spec = 'x:' + module.namespace + '.' + struct.name
199 module.kinds[struct.spec] = struct
200 struct.enums = map(lambda enum:
201 EnumFromData(module, enum, struct), data['enums'])
202 struct.constants = map(lambda constant:
203 ConstantFromData(module, constant, struct), data['constants'])
204 # Stash fields data here temporarily.
205 struct.fields_data = data['fields']
206 return struct
207
208 def UnionToData(union):
209 return {
210 istr(0, 'name'): union.name,
211 istr(1, 'fields'): map(FieldToData, union.fields)
212 }
213
214 def UnionFromData(module, data):
215 union = mojom.Union(module=module)
216 union.name = data['name']
217 union.spec = 'x:' + module.namespace + '.' + union.name
218 module.kinds[union.spec] = union
219 # Stash fields data here temporarily.
220 union.fields_data = data['fields']
221 return union
222
223 def FieldToData(field):
224 data = {
225 istr(0, 'name'): field.name,
226 istr(1, 'kind'): KindToData(field.kind)
227 }
228 if field.ordinal != None:
229 data[istr(2, 'ordinal')] = field.ordinal
230 if field.default != None:
231 data[istr(3, 'default')] = field.default
232 return data
233
234 def FieldFromData(module, data, struct):
235 field = mojom.Field()
236 field.name = data['name']
237 field.kind = KindFromData(
238 module.kinds, data['kind'], (module.namespace, struct.name))
239 field.ordinal = data.get('ordinal')
240 field.default = FixupExpression(
241 module, data.get('default'), (module.namespace, struct.name), field.kind)
242 return field
243
244 def ParameterToData(parameter):
245 data = {
246 istr(0, 'name'): parameter.name,
247 istr(1, 'kind'): parameter.kind.spec
248 }
249 if parameter.ordinal != None:
250 data[istr(2, 'ordinal')] = parameter.ordinal
251 if parameter.default != None:
252 data[istr(3, 'default')] = parameter.default
253 return data
254
255 def ParameterFromData(module, data, interface):
256 parameter = mojom.Parameter()
257 parameter.name = data['name']
258 parameter.kind = KindFromData(
259 module.kinds, data['kind'], (module.namespace, interface.name))
260 parameter.ordinal = data.get('ordinal')
261 parameter.default = data.get('default')
262 return parameter
263
264 def MethodToData(method):
265 data = {
266 istr(0, 'name'): method.name,
267 istr(1, 'parameters'): map(ParameterToData, method.parameters)
268 }
269 if method.ordinal != None:
270 data[istr(2, 'ordinal')] = method.ordinal
271 if method.response_parameters != None:
272 data[istr(3, 'response_parameters')] = map(
273 ParameterToData, method.response_parameters)
274 return data
275
276 def MethodFromData(module, data, interface):
277 method = mojom.Method(interface, data['name'], ordinal=data.get('ordinal'))
278 method.default = data.get('default')
279 method.parameters = map(lambda parameter:
280 ParameterFromData(module, parameter, interface), data['parameters'])
281 if data.has_key('response_parameters'):
282 method.response_parameters = map(
283 lambda parameter: ParameterFromData(module, parameter, interface),
284 data['response_parameters'])
285 return method
286
287 def InterfaceToData(interface):
288 return {
289 istr(0, 'name'): interface.name,
290 istr(1, 'client'): interface.client,
291 istr(2, 'methods'): map(MethodToData, interface.methods)
292 }
293
294 def InterfaceFromData(module, data):
295 interface = mojom.Interface(module=module)
296 interface.name = data['name']
297 interface.spec = 'x:' + module.namespace + '.' + interface.name
298 interface.client = data['client'] if data.has_key('client') else None
299 module.kinds[interface.spec] = interface
300 interface.enums = map(lambda enum:
301 EnumFromData(module, enum, interface), data['enums'])
302 interface.constants = map(lambda constant:
303 ConstantFromData(module, constant, interface), data['constants'])
304 # Stash methods data here temporarily.
305 interface.methods_data = data['methods']
306 return interface
307
308 def EnumFieldFromData(module, enum, data, parent_kind):
309 field = mojom.EnumField()
310 field.name = data['name']
311 # TODO(mpcomplete): FixupExpression should be done in the second pass,
312 # so constants and enums can refer to each other.
313 # TODO(mpcomplete): But then, what if constants are initialized to an enum? Or
314 # vice versa?
315 if parent_kind:
316 field.value = FixupExpression(
317 module, data['value'], (module.namespace, parent_kind.name), enum)
318 else:
319 field.value = FixupExpression(
320 module, data['value'], (module.namespace, ), enum)
321 value = mojom.EnumValue(module, enum, field)
322 module.values[value.GetSpec()] = value
323 return field
324
325 def EnumFromData(module, data, parent_kind):
326 enum = mojom.Enum(module=module)
327 enum.name = data['name']
328 name = enum.name
329 if parent_kind:
330 name = parent_kind.name + '.' + name
331 enum.spec = 'x:%s.%s' % (module.namespace, name)
332 enum.parent_kind = parent_kind
333
334 enum.fields = map(
335 lambda field: EnumFieldFromData(module, enum, field, parent_kind),
336 data['fields'])
337 module.kinds[enum.spec] = enum
338 return enum
339
340 def ConstantFromData(module, data, parent_kind):
341 constant = mojom.Constant()
342 constant.name = data['name']
343 if parent_kind:
344 scope = (module.namespace, parent_kind.name)
345 else:
346 scope = (module.namespace, )
347 # TODO(mpcomplete): maybe we should only support POD kinds.
348 constant.kind = KindFromData(module.kinds, data['kind'], scope)
349 constant.value = FixupExpression(module, data.get('value'), scope, None)
350
351 value = mojom.ConstantValue(module, parent_kind, constant)
352 module.values[value.GetSpec()] = value
353 return constant
354
355 def ModuleToData(module):
356 return {
357 istr(0, 'name'): module.name,
358 istr(1, 'namespace'): module.namespace,
359 istr(2, 'structs'): map(StructToData, module.structs),
360 istr(3, 'interfaces'): map(InterfaceToData, module.interfaces),
361 istr(4, 'unions'): map(UnionToData, module.unions),
362 }
363
364 def ModuleFromData(data):
365 module = mojom.Module()
366 module.kinds = {}
367 for kind in mojom.PRIMITIVES:
368 module.kinds[kind.spec] = kind
369
370 module.values = {}
371
372 module.name = data['name']
373 module.namespace = data['namespace']
374 module.attributes = data['attributes']
375 # Imports must come first, because they add to module.kinds which is used
376 # by by the others.
377 module.imports = map(
378 lambda import_data: ImportFromData(module, import_data),
379 data['imports'])
380
381 # First pass collects kinds.
382 module.enums = map(
383 lambda enum: EnumFromData(module, enum, None), data['enums'])
384 module.structs = map(
385 lambda struct: StructFromData(module, struct), data['structs'])
386 module.unions = map(
387 lambda union: UnionFromData(module, struct), data.get('unions', []))
388 module.interfaces = map(
389 lambda interface: InterfaceFromData(module, interface),
390 data['interfaces'])
391 module.constants = map(
392 lambda constant: ConstantFromData(module, constant, None),
393 data['constants'])
394
395 # Second pass expands fields and methods. This allows fields and parameters
396 # to refer to kinds defined anywhere in the mojom.
397 for struct in module.structs:
398 struct.fields = map(lambda field:
399 FieldFromData(module, field, struct), struct.fields_data)
400 del struct.fields_data
401 for union in module.unions:
402 union.fields = map(lambda field:
403 FieldFromData(module, field, union), union.fields_data)
404 del union.fields_data
405 for interface in module.interfaces:
406 interface.methods = map(lambda method:
407 MethodFromData(module, method, interface), interface.methods_data)
408 del interface.methods_data
409
410 return module
411
412 def OrderedModuleFromData(data):
413 module = ModuleFromData(data)
414 for interface in module.interfaces:
415 next_ordinal = 0
416 for method in interface.methods:
417 if method.ordinal is None:
418 method.ordinal = next_ordinal
419 next_ordinal = method.ordinal + 1
420 return module
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698