1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)# found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch# TODO(vtl): "data" is a pretty vague name. Rename it?
60529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import copy
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
90529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport module as mojom
100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch# This module provides a mechanism to turn mojom Modules to dictionaries and
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)# back again. This can be used to persist a mojom Module created progromatically
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)# or to read a dictionary from code or a file.
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)# Example:
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)# test_dict = {
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#   'name': 'test',
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#   'namespace': 'testspace',
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#   'structs': [{
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#     'name': 'teststruct',
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#     'fields': [
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#       {'name': 'testfield1', 'kind': 'i32'},
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#       {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}],
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#   'interfaces': [{
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#     'name': 'Server',
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#     'methods': [{
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#       'name': 'Foo',
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#       'parameters': [{
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#         'name': 'foo', 'kind': 'i32'},
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#         {'name': 'bar', 'kind': 'a:x:teststruct'}],
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#     'ordinal': 42}]}]
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)# }
320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch# test_module = data.ModuleFromData(test_dict)
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)# Used to create a subclass of str that supports sorting by index, to make
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)# pretty printing maintain the order.
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def istr(index, string):
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  class IndexedString(str):
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    def __lt__(self, other):
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return self.__index__ < other.__index__
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  rv = IndexedString(string)
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  rv.__index__ = index
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return rv
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibuiltin_values = frozenset([
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    "double.INFINITY",
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    "double.NEGATIVE_INFINITY",
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    "double.NAN",
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    "float.INFINITY",
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    "float.NEGATIVE_INFINITY",
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    "float.NAN"])
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef IsBuiltinValue(value):
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return value in builtin_values
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def LookupKind(kinds, spec, scope):
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """Tries to find which Kind a spec refers to, given the scope in which its
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  referenced. Starts checking from the narrowest scope to most general. For
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  example, given a struct field like
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    Foo.Bar x;
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Foo.Bar could refer to the type 'Bar' in the 'Foo' namespace, or an inner
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  type 'Bar' in the struct 'Foo' in the current namespace.
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  |scope| is a tuple that looks like (namespace, struct/interface), referring
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  to the location where the type is referenced."""
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if spec.startswith('x:'):
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    name = spec[2:]
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for i in xrange(len(scope), -1, -1):
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      test_spec = 'x:'
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if i > 0:
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        test_spec += '.'.join(scope[:i]) + '.'
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      test_spec += name
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kind = kinds.get(test_spec)
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if kind:
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        return kind
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return kinds.get(spec)
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdef LookupValue(values, name, scope, kind):
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """Like LookupKind, but for constant values."""
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  # If the type is an enum, the value can be specified as a qualified name, in
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  # which case the form EnumName.ENUM_VALUE must be used. We use the presence
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  # of a '.' in the requested name to identify this. Otherwise, we prepend the
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  # enum name.
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if isinstance(kind, mojom.Enum) and '.' not in name:
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    name = '%s.%s' % (kind.spec.split(':', 1)[1], name)
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for i in reversed(xrange(len(scope) + 1)):
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    test_spec = '.'.join(scope[:i])
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if test_spec:
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      test_spec += '.'
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    test_spec += name
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    value = values.get(test_spec)
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if value:
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return value
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return values.get(name)
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdef FixupExpression(module, value, scope, kind):
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  """Translates an IDENTIFIER into a built-in value or structured NamedValue
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     object."""
10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if isinstance(value, tuple) and value[0] == 'IDENTIFIER':
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # Allow user defined values to shadow builtins.
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    result = LookupValue(module.values, value[1], scope, kind)
10446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if result:
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if isinstance(result, tuple):
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        raise Exception('Unable to resolve expression: %r' % value[1])
10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return result
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if IsBuiltinValue(value[1]):
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return mojom.BuiltinValue(value[1])
11046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return value
11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def KindToData(kind):
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return kind.spec
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def KindFromData(kinds, data, scope):
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  kind = LookupKind(kinds, data, scope)
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if kind:
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return kind
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if data.startswith('?'):
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    kind = KindFromData(kinds, data[1:], scope).MakeNullableKind()
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  elif data.startswith('a:'):
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    kind = mojom.Array(KindFromData(kinds, data[2:], scope))
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  elif data.startswith('r:'):
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    kind = mojom.InterfaceRequest(KindFromData(kinds, data[2:], scope))
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  elif data.startswith('a'):
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    colon = data.find(':')
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    length = int(data[1:colon])
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    kind = mojom.FixedArray(length, KindFromData(kinds, data[colon+1:], scope))
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  else:
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    kind = mojom.Kind(data)
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  kinds[data] = kind
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return kind
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def KindFromImport(original_kind, imported_from):
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """Used with 'import module' - clones the kind imported from the given
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  module's namespace. Only used with Structs, Interfaces and Enums."""
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  kind = copy.copy(original_kind)
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # |shared_definition| is used to store various properties (see
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # |AddSharedProperty()| in module.py), including |imported_from|. We don't
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # want the copy to share these with the original, so copy it if necessary.
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if hasattr(original_kind, 'shared_definition'):
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    kind.shared_definition = copy.copy(original_kind.shared_definition)
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  kind.imported_from = imported_from
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return kind
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def ImportFromData(module, data):
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  import_module = data['module']
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  import_item = {}
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  import_item['module_name'] = import_module.name
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  import_item['namespace'] = import_module.namespace
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  import_item['module'] = import_module
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Copy the struct kinds from our imports into the current module.
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for kind in import_module.kinds.itervalues():
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (isinstance(kind, (mojom.Struct, mojom.Enum, mojom.Interface)) and
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        kind.imported_from is None):
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kind = KindFromImport(kind, import_item)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      module.kinds[kind.spec] = kind
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # Ditto for values.
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for value in import_module.values.itervalues():
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if value.imported_from is None:
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # Values don't have shared definitions (since they're not nullable), so no
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # need to do anything special.
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      value = copy.copy(value)
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      value.imported_from = import_item
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      module.values[value.GetSpec()] = value
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return import_item
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def StructToData(struct):
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return {
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(0, 'name'): struct.name,
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(1, 'fields'): map(FieldToData, struct.fields)
1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def StructFromData(module, data):
1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  struct = mojom.Struct(module=module)
1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  struct.name = data['name']
182010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  struct.attributes = data['attributes']
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  struct.spec = 'x:' + module.namespace + '.' + struct.name
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  module.kinds[struct.spec] = struct
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  struct.enums = map(lambda enum:
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      EnumFromData(module, enum, struct), data['enums'])
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  struct.constants = map(lambda constant:
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ConstantFromData(module, constant, struct), data['constants'])
1890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  # Stash fields data here temporarily.
1900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  struct.fields_data = data['fields']
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return struct
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def FieldToData(field):
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  data = {
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(0, 'name'): field.name,
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(1, 'kind'): KindToData(field.kind)
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if field.ordinal != None:
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    data[istr(2, 'ordinal')] = field.ordinal
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if field.default != None:
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    data[istr(3, 'default')] = field.default
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return data
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def FieldFromData(module, data, struct):
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  field = mojom.Field()
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  field.name = data['name']
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  field.kind = KindFromData(
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      module.kinds, data['kind'], (module.namespace, struct.name))
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  field.ordinal = data.get('ordinal')
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  field.default = FixupExpression(
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      module, data.get('default'), (module.namespace, struct.name), field.kind)
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return field
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def ParameterToData(parameter):
2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  data = {
2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(0, 'name'): parameter.name,
2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(1, 'kind'): parameter.kind.spec
2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if parameter.ordinal != None:
2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    data[istr(2, 'ordinal')] = parameter.ordinal
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if parameter.default != None:
2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    data[istr(3, 'default')] = parameter.default
2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return data
2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def ParameterFromData(module, data, interface):
2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  parameter = mojom.Parameter()
2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  parameter.name = data['name']
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  parameter.kind = KindFromData(
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      module.kinds, data['kind'], (module.namespace, interface.name))
2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  parameter.ordinal = data.get('ordinal')
2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  parameter.default = data.get('default')
2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return parameter
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def MethodToData(method):
2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  data = {
2364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(0, 'name'):       method.name,
2374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(1, 'parameters'): map(ParameterToData, method.parameters)
2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if method.ordinal != None:
2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    data[istr(2, 'ordinal')] = method.ordinal
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if method.response_parameters != None:
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    data[istr(3, 'response_parameters')] = map(
243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        ParameterToData, method.response_parameters)
2444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return data
2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def MethodFromData(module, data, interface):
247010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  method = mojom.Method(interface, data['name'], ordinal=data.get('ordinal'))
2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  method.default = data.get('default')
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  method.parameters = map(lambda parameter:
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ParameterFromData(module, parameter, interface), data['parameters'])
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if data.has_key('response_parameters'):
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    method.response_parameters = map(
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        lambda parameter: ParameterFromData(module, parameter, interface),
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                          data['response_parameters'])
2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return method
2564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def InterfaceToData(interface):
2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return {
2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(0, 'name'):    interface.name,
2600de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    istr(1, 'client'):  interface.client,
261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    istr(2, 'methods'): map(MethodToData, interface.methods)
2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def InterfaceFromData(module, data):
2655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  interface = mojom.Interface(module=module)
2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  interface.name = data['name']
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  interface.spec = 'x:' + module.namespace + '.' + interface.name
2680de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  interface.client = data['client'] if data.has_key('client') else None
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  module.kinds[interface.spec] = interface
270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  interface.enums = map(lambda enum:
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      EnumFromData(module, enum, interface), data['enums'])
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  interface.constants = map(lambda constant:
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ConstantFromData(module, constant, interface), data['constants'])
2740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  # Stash methods data here temporarily.
2750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  interface.methods_data = data['methods']
2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return interface
2774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def EnumFieldFromData(module, enum, data, parent_kind):
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  field = mojom.EnumField()
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  field.name = data['name']
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # TODO(mpcomplete): FixupExpression should be done in the second pass,
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # so constants and enums can refer to each other.
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # TODO(mpcomplete): But then, what if constants are initialized to an enum? Or
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # vice versa?
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if parent_kind:
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    field.value = FixupExpression(
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        module, data['value'], (module.namespace, parent_kind.name), enum)
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  else:
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    field.value = FixupExpression(
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        module, data['value'], (module.namespace, ), enum)
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  value = mojom.EnumValue(module, enum, field)
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  module.values[value.GetSpec()] = value
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return field
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def EnumFromData(module, data, parent_kind):
2965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  enum = mojom.Enum(module=module)
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  enum.name = data['name']
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  name = enum.name
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if parent_kind:
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    name = parent_kind.name + '.' + name
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  enum.spec = 'x:%s.%s' % (module.namespace, name)
302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  enum.parent_kind = parent_kind
303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  enum.fields = map(
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      lambda field: EnumFieldFromData(module, enum, field, parent_kind),
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      data['fields'])
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  module.kinds[enum.spec] = enum
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return enum
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)def ConstantFromData(module, data, parent_kind):
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  constant = mojom.Constant()
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  constant.name = data['name']
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if parent_kind:
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scope = (module.namespace, parent_kind.name)
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  else:
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scope = (module.namespace, )
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # TODO(mpcomplete): maybe we should only support POD kinds.
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  constant.kind = KindFromData(module.kinds, data['kind'], scope)
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  constant.value = FixupExpression(module, data.get('value'), scope, None)
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  value = mojom.ConstantValue(module, parent_kind, constant)
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  module.values[value.GetSpec()] = value
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return constant
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def ModuleToData(module):
3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return {
3274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(0, 'name'):       module.name,
3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(1, 'namespace'):  module.namespace,
3294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(2, 'structs'):    map(StructToData, module.structs),
3304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    istr(3, 'interfaces'): map(InterfaceToData, module.interfaces)
3314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
3324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def ModuleFromData(data):
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  module = mojom.Module()
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  module.kinds = {}
3364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for kind in mojom.PRIMITIVES:
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    module.kinds[kind.spec] = kind
3384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  module.values = {}
340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  module.name = data['name']
3424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  module.namespace = data['namespace']
343010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  module.attributes = data['attributes']
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Imports must come first, because they add to module.kinds which is used
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # by by the others.
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  module.imports = map(
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      lambda import_data: ImportFromData(module, import_data),
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      data['imports'])
3490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  # First pass collects kinds.
351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  module.enums = map(
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      lambda enum: EnumFromData(module, enum, None), data['enums'])
3534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  module.structs = map(
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      lambda struct: StructFromData(module, struct), data['structs'])
3554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  module.interfaces = map(
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      lambda interface: InterfaceFromData(module, interface),
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      data['interfaces'])
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  module.constants = map(
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      lambda constant: ConstantFromData(module, constant, None),
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      data['constants'])
361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  # Second pass expands fields and methods. This allows fields and parameters
3630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  # to refer to kinds defined anywhere in the mojom.
3640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for struct in module.structs:
3650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    struct.fields = map(lambda field:
3660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        FieldFromData(module, field, struct), struct.fields_data)
3670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    del struct.fields_data
3680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for interface in module.interfaces:
3690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    interface.methods = map(lambda method:
3700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        MethodFromData(module, method, interface), interface.methods_data)
3710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    del interface.methods_data
3720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return module
3744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)def OrderedModuleFromData(data):
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  module = ModuleFromData(data)
377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for interface in module.interfaces:
378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    next_ordinal = 0
379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for method in interface.methods:
380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if method.ordinal is None:
381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        method.ordinal = next_ordinal
382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      next_ordinal = method.ordinal + 1
383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return module
384