Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / mojo / public / bindings / pylib / generate / mojom_data.py
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 import mojom
6 import copy
7
8 # mojom_data provides a mechanism to turn mojom Modules to dictionaries and
9 # back again. This can be used to persist a mojom Module created progromatically
10 # or to read a dictionary from code or a file.
11 # Example:
12 # test_dict = {
13 #   'name': 'test',
14 #   'namespace': 'testspace',
15 #   'structs': [{
16 #     'name': 'teststruct',
17 #     'fields': [
18 #       {'name': 'testfield1', 'kind': 'i32'},
19 #       {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}],
20 #   'interfaces': [{
21 #     'name': 'Server',
22 #     'methods': [{
23 #       'name': 'Foo',
24 #       'parameters': [{
25 #         'name': 'foo', 'kind': 'i32'},
26 #         {'name': 'bar', 'kind': 'a:x:teststruct'}],
27 #     'ordinal': 42}]}]
28 # }
29 # test_module = mojom_data.ModuleFromData(test_dict)
30
31 # Used to create a subclass of str that supports sorting by index, to make
32 # pretty printing maintain the order.
33 def istr(index, string):
34   class IndexedString(str):
35     def __lt__(self, other):
36       return self.__index__ < other.__index__
37
38   istr = IndexedString(string)
39   istr.__index__ = index
40   return istr
41
42 def LookupKind(kinds, spec, scope):
43   """Tries to find which Kind a spec refers to, given the scope in which its
44   referenced. Starts checking from the narrowest scope to most general. For
45   example, given a struct field like
46     Foo.Bar x;
47   Foo.Bar could refer to the type 'Bar' in the 'Foo' namespace, or an inner
48   type 'Bar' in the struct 'Foo' in the current namespace.
49
50   |scope| is a tuple that looks like (namespace, struct/interface), referring
51   to the location where the type is referenced."""
52   if spec.startswith('x:'):
53     name = spec[2:]
54     for i in xrange(len(scope), -1, -1):
55       test_spec = 'x:'
56       if i > 0:
57         test_spec += '.'.join(scope[:i]) + '.'
58       test_spec += name
59       kind = kinds.get(test_spec)
60       if kind:
61         return kind
62
63   return kinds.get(spec)
64
65 def LookupConstant(constants, name, scope):
66   """Like LookupKind, but for constants."""
67   for i in xrange(len(scope), -1, -1):
68     if i > 0:
69       test_spec = '.'.join(scope[:i]) + '.'
70     test_spec += name
71     constant = constants.get(test_spec)
72     if constant:
73       return constant
74
75   return constants.get(name)
76
77 def KindToData(kind):
78   return kind.spec
79
80 def KindFromData(kinds, data, scope):
81   kind = LookupKind(kinds, data, scope)
82   if kind:
83     return kind
84   if data.startswith('a:'):
85     kind = mojom.Array()
86     kind.kind = KindFromData(kinds, data[2:], scope)
87   else:
88     kind = mojom.Kind()
89   kind.spec = data
90   kinds[data] = kind
91   return kind
92
93 def KindFromImport(original_kind, imported_from):
94   """Used with 'import module' - clones the kind imported from the
95   given module's namespace. Only used with Structs and Enums."""
96   kind = copy.deepcopy(original_kind)
97   kind.imported_from = imported_from
98   return kind
99
100 def ImportFromData(module, data):
101   import_module = data['module']
102
103   import_item = {}
104   import_item['module_name'] = import_module.name
105   import_item['namespace'] = import_module.namespace
106   import_item['module'] = import_module
107
108   # Copy the struct kinds from our imports into the current module.
109   for kind in import_module.kinds.itervalues():
110     if (isinstance(kind, (mojom.Struct, mojom.Enum)) and
111         kind.imported_from is None):
112       kind = KindFromImport(kind, import_item)
113       module.kinds[kind.spec] = kind
114   # Ditto for constants.
115   for constant in import_module.constants.itervalues():
116     if constant.imported_from is None:
117       constant = copy.deepcopy(constant)
118       constant.imported_from = import_item
119       module.constants[constant.GetSpec()] = constant
120
121   return import_item
122
123 def StructToData(struct):
124   return {
125     istr(0, 'name'): struct.name,
126     istr(1, 'fields'): map(FieldToData, struct.fields)
127   }
128
129 def StructFromData(module, data):
130   struct = mojom.Struct()
131   struct.name = data['name']
132   struct.spec = 'x:' + module.namespace + '.' + struct.name
133   module.kinds[struct.spec] = struct
134   struct.enums = map(lambda enum:
135       EnumFromData(module, enum, struct), data['enums'])
136   struct.fields = map(lambda field:
137       FieldFromData(module, field, struct), data['fields'])
138   return struct
139
140 def FieldToData(field):
141   data = {
142     istr(0, 'name'): field.name,
143     istr(1, 'kind'): KindToData(field.kind)
144   }
145   if field.ordinal != None:
146     data[istr(2, 'ordinal')] = field.ordinal
147   if field.default != None:
148     data[istr(3, 'default')] = field.default
149   return data
150
151 def FixupExpression(module, value, scope):
152   if isinstance(value, (tuple, list)):
153     for i in xrange(len(value)):
154       if isinstance(value, tuple):
155         FixupExpression(module, value[i], scope)
156       else:
157         value[i] = FixupExpression(module, value[i], scope)
158   elif value:
159     constant = LookupConstant(module.constants, value, scope)
160     if constant:
161       return constant
162   return value
163
164 def FieldFromData(module, data, struct):
165   field = mojom.Field()
166   field.name = data['name']
167   field.kind = KindFromData(
168       module.kinds, data['kind'], (module.namespace, struct.name))
169   field.ordinal = data.get('ordinal')
170   field.default = FixupExpression(
171       module, data.get('default'), (module.namespace, struct.name))
172   return field
173
174 def ParameterToData(parameter):
175   data = {
176     istr(0, 'name'): parameter.name,
177     istr(1, 'kind'): parameter.kind.spec
178   }
179   if parameter.ordinal != None:
180     data[istr(2, 'ordinal')] = parameter.ordinal
181   if parameter.default != None:
182     data[istr(3, 'default')] = parameter.default
183   return data
184
185 def ParameterFromData(module, data, interface):
186   parameter = mojom.Parameter()
187   parameter.name = data['name']
188   parameter.kind = KindFromData(
189       module.kinds, data['kind'], (module.namespace, interface.name))
190   parameter.ordinal = data.get('ordinal')
191   parameter.default = data.get('default')
192   return parameter
193
194 def MethodToData(method):
195   data = {
196     istr(0, 'name'):       method.name,
197     istr(1, 'parameters'): map(ParameterToData, method.parameters)
198   }
199   if method.ordinal != None:
200     data[istr(2, 'ordinal')] = method.ordinal
201   if method.response_parameters != None:
202     data[istr(3, 'response_parameters')] = map(
203         ParameterToData, method.response_parameters)
204   return data
205
206 def MethodFromData(module, data, interface):
207   method = mojom.Method()
208   method.name = data['name']
209   method.ordinal = data.get('ordinal')
210   method.default = data.get('default')
211   method.parameters = map(lambda parameter:
212       ParameterFromData(module, parameter, interface), data['parameters'])
213   if data.has_key('response_parameters'):
214     method.response_parameters = map(
215         lambda parameter: ParameterFromData(module, parameter, interface),
216                           data['response_parameters'])
217   return method
218
219 def InterfaceToData(interface):
220   return {
221     istr(0, 'name'):    interface.name,
222     istr(1, 'peer'):    interface.peer,
223     istr(2, 'methods'): map(MethodToData, interface.methods)
224   }
225
226 def InterfaceFromData(module, data):
227   interface = mojom.Interface()
228   interface.name = data['name']
229   interface.spec = 'x:' + module.namespace + '.' + interface.name
230   interface.peer = data['peer'] if data.has_key('peer') else None
231   module.kinds[interface.spec] = interface
232   interface.enums = map(lambda enum:
233       EnumFromData(module, enum, interface), data['enums'])
234   interface.methods = map(lambda method:
235       MethodFromData(module, method, interface), data['methods'])
236   return interface
237
238 def EnumFieldFromData(module, enum, data, parent_kind):
239   field = mojom.EnumField()
240   field.name = data['name']
241   if parent_kind:
242     field.value = FixupExpression(
243         module, data['value'], (module.namespace, parent_kind.name))
244   else:
245     field.value = FixupExpression(
246         module, data['value'], (module.namespace, ))
247   constant = mojom.Constant(module, enum, field)
248   module.constants[constant.GetSpec()] = constant
249   return field
250
251 def EnumFromData(module, data, parent_kind):
252   enum = mojom.Enum()
253   enum.name = data['name']
254   name = enum.name
255   if parent_kind:
256     name = parent_kind.name + '.' + name
257   enum.spec = 'x:%s.%s' % (module.namespace, name)
258   enum.parent_kind = parent_kind
259
260   enum.fields = map(
261       lambda field: EnumFieldFromData(module, enum, field, parent_kind),
262       data['fields'])
263   module.kinds[enum.spec] = enum
264   return enum
265
266 def ModuleToData(module):
267   return {
268     istr(0, 'name'):       module.name,
269     istr(1, 'namespace'):  module.namespace,
270     istr(2, 'structs'):    map(StructToData, module.structs),
271     istr(3, 'interfaces'): map(InterfaceToData, module.interfaces)
272   }
273
274 def ModuleFromData(data):
275   module = mojom.Module()
276   module.kinds = {}
277   for kind in mojom.PRIMITIVES:
278     module.kinds[kind.spec] = kind
279
280   module.constants = {}
281
282   module.name = data['name']
283   module.namespace = data['namespace']
284   # Imports must come first, because they add to module.kinds which is used
285   # by by the others.
286   module.imports = map(
287       lambda import_data: ImportFromData(module, import_data),
288       data['imports'])
289   module.enums = map(
290       lambda enum: EnumFromData(module, enum, None), data['enums'])
291   module.structs = map(
292       lambda struct: StructFromData(module, struct), data['structs'])
293   module.interfaces = map(
294       lambda interface: InterfaceFromData(module, interface),
295       data['interfaces'])
296
297   return module
298
299 def OrderedModuleFromData(data):
300   module = ModuleFromData(data)
301   next_interface_ordinal = 0
302   for interface in module.interfaces:
303     next_ordinal = 0
304     for method in interface.methods:
305       if method.ordinal is None:
306         method.ordinal = next_ordinal
307       next_ordinal = method.ordinal + 1
308   return module