xref: /aosp_15_r20/external/libchrome/mojo/public/tools/bindings/pylib/mojom/generate/module.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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# This module's classes provide an interface to mojo modules. Modules are
6# collections of interfaces and structs to be used by mojo ipc clients and
7# servers.
8#
9# A simple interface would be created this way:
10# module = mojom.generate.module.Module('Foo')
11# interface = module.AddInterface('Bar')
12# method = interface.AddMethod('Tat', 0)
13# method.AddParameter('baz', 0, mojom.INT32)
14
15from uuid import UUID
16
17# We use our own version of __repr__ when displaying the AST, as the
18# AST currently doesn't capture which nodes are reference (e.g. to
19# types) and which nodes are definitions. This allows us to e.g. print
20# the definition of a struct when it's defined inside a module, but
21# only print its name when it's referenced in e.g. a method parameter.
22def Repr(obj, as_ref=True):
23  """A version of __repr__ that can distinguish references.
24
25  Sometimes we like to print an object's full representation
26  (e.g. with its fields) and sometimes we just want to reference an
27  object that was printed in full elsewhere. This function allows us
28  to make that distinction.
29
30  Args:
31    obj: The object whose string representation we compute.
32    as_ref: If True, use the short reference representation.
33
34  Returns:
35    A str representation of |obj|.
36  """
37  if hasattr(obj, 'Repr'):
38    return obj.Repr(as_ref=as_ref)
39  # Since we cannot implement Repr for existing container types, we
40  # handle them here.
41  elif isinstance(obj, list):
42    if not obj:
43      return '[]'
44    else:
45      return ('[\n%s\n]' % (',\n'.join('    %s' % Repr(elem, as_ref).replace(
46          '\n', '\n    ') for elem in obj)))
47  elif isinstance(obj, dict):
48    if not obj:
49      return '{}'
50    else:
51      return ('{\n%s\n}' % (',\n'.join('    %s: %s' % (
52          Repr(key, as_ref).replace('\n', '\n    '),
53          Repr(val, as_ref).replace('\n', '\n    '))
54          for key, val in obj.items())))
55  else:
56    return repr(obj)
57
58
59def GenericRepr(obj, names):
60  """Compute generic Repr for |obj| based on the attributes in |names|.
61
62  Args:
63    obj: The object to compute a Repr for.
64    names: A dict from attribute names to include, to booleans
65        specifying whether those attributes should be shown as
66        references or not.
67
68  Returns:
69    A str representation of |obj|.
70  """
71  def ReprIndent(name, as_ref):
72    return '    %s=%s' % (name, Repr(getattr(obj, name), as_ref).replace(
73        '\n', '\n    '))
74
75  return '%s(\n%s\n)' % (
76      obj.__class__.__name__,
77      ',\n'.join(ReprIndent(name, as_ref)
78                 for (name, as_ref) in names.items()))
79
80
81class Kind(object):
82  """Kind represents a type (e.g. int8, string).
83
84  Attributes:
85    spec: A string uniquely identifying the type. May be None.
86    module: {Module} The defining module. Set to None for built-in types.
87    parent_kind: The enclosing type. For example, an enum defined
88        inside an interface has that interface as its parent. May be None.
89  """
90  def __init__(self, spec=None, module=None):
91    self.spec = spec
92    self.module = module
93    self.parent_kind = None
94
95  def Repr(self, as_ref=True):
96    return '<%s spec=%r>' % (self.__class__.__name__, self.spec)
97
98  def __repr__(self):
99    # Gives us a decent __repr__ for all kinds.
100    return self.Repr()
101
102
103class ReferenceKind(Kind):
104  """ReferenceKind represents pointer and handle types.
105
106  A type is nullable if null (for pointer types) or invalid handle (for handle
107  types) is a legal value for the type.
108
109  Attributes:
110    is_nullable: True if the type is nullable.
111  """
112  def __init__(self, spec=None, is_nullable=False, module=None):
113    assert spec is None or is_nullable == spec.startswith('?')
114    Kind.__init__(self, spec, module)
115    self.is_nullable = is_nullable
116    self.shared_definition = {}
117
118  def Repr(self, as_ref=True):
119    return '<%s spec=%r is_nullable=%r>' % (self.__class__.__name__, self.spec,
120                                            self.is_nullable)
121
122  def MakeNullableKind(self):
123    assert not self.is_nullable
124
125    if self == STRING:
126      return NULLABLE_STRING
127    if self == HANDLE:
128      return NULLABLE_HANDLE
129    if self == DCPIPE:
130      return NULLABLE_DCPIPE
131    if self == DPPIPE:
132      return NULLABLE_DPPIPE
133    if self == MSGPIPE:
134      return NULLABLE_MSGPIPE
135    if self == SHAREDBUFFER:
136      return NULLABLE_SHAREDBUFFER
137
138    nullable_kind = type(self)()
139    nullable_kind.shared_definition = self.shared_definition
140    if self.spec is not None:
141      nullable_kind.spec = '?' + self.spec
142    nullable_kind.is_nullable = True
143    nullable_kind.parent_kind = self.parent_kind
144    nullable_kind.module = self.module
145
146    return nullable_kind
147
148  @classmethod
149  def AddSharedProperty(cls, name):
150    """Adds a property |name| to |cls|, which accesses the corresponding item in
151       |shared_definition|.
152
153       The reason of adding such indirection is to enable sharing definition
154       between a reference kind and its nullable variation. For example:
155         a = Struct('test_struct_1')
156         b = a.MakeNullableKind()
157         a.name = 'test_struct_2'
158         print b.name  # Outputs 'test_struct_2'.
159    """
160    def Get(self):
161      try:
162        return self.shared_definition[name]
163      except KeyError:
164        raise AttributeError()
165
166    def Set(self, value):
167      self.shared_definition[name] = value
168
169    setattr(cls, name, property(Get, Set))
170
171
172# Initialize the set of primitive types. These can be accessed by clients.
173BOOL                  = Kind('b')
174INT8                  = Kind('i8')
175INT16                 = Kind('i16')
176INT32                 = Kind('i32')
177INT64                 = Kind('i64')
178UINT8                 = Kind('u8')
179UINT16                = Kind('u16')
180UINT32                = Kind('u32')
181UINT64                = Kind('u64')
182FLOAT                 = Kind('f')
183DOUBLE                = Kind('d')
184STRING                = ReferenceKind('s')
185HANDLE                = ReferenceKind('h')
186DCPIPE                = ReferenceKind('h:d:c')
187DPPIPE                = ReferenceKind('h:d:p')
188MSGPIPE               = ReferenceKind('h:m')
189SHAREDBUFFER          = ReferenceKind('h:s')
190NULLABLE_STRING       = ReferenceKind('?s', True)
191NULLABLE_HANDLE       = ReferenceKind('?h', True)
192NULLABLE_DCPIPE       = ReferenceKind('?h:d:c', True)
193NULLABLE_DPPIPE       = ReferenceKind('?h:d:p', True)
194NULLABLE_MSGPIPE      = ReferenceKind('?h:m', True)
195NULLABLE_SHAREDBUFFER = ReferenceKind('?h:s', True)
196
197
198# Collection of all Primitive types
199PRIMITIVES = (
200  BOOL,
201  INT8,
202  INT16,
203  INT32,
204  INT64,
205  UINT8,
206  UINT16,
207  UINT32,
208  UINT64,
209  FLOAT,
210  DOUBLE,
211  STRING,
212  HANDLE,
213  DCPIPE,
214  DPPIPE,
215  MSGPIPE,
216  SHAREDBUFFER,
217  NULLABLE_STRING,
218  NULLABLE_HANDLE,
219  NULLABLE_DCPIPE,
220  NULLABLE_DPPIPE,
221  NULLABLE_MSGPIPE,
222  NULLABLE_SHAREDBUFFER
223)
224
225
226ATTRIBUTE_MIN_VERSION = 'MinVersion'
227ATTRIBUTE_EXTENSIBLE = 'Extensible'
228ATTRIBUTE_SYNC = 'Sync'
229ATTRIBUTE_UUID = 'Uuid'
230
231
232class NamedValue(object):
233  def __init__(self, module, parent_kind, mojom_name):
234    self.module = module
235    self.parent_kind = parent_kind
236    self.mojom_name = mojom_name
237
238  def GetSpec(self):
239    return (self.module.mojom_namespace + '.' +
240        (self.parent_kind and (self.parent_kind.mojom_name + '.') or "") +
241        self.mojom_name)
242
243
244class BuiltinValue(object):
245  def __init__(self, value):
246    self.value = value
247
248
249class ConstantValue(NamedValue):
250  def __init__(self, module, parent_kind, constant):
251    NamedValue.__init__(self, module, parent_kind, constant.mojom_name)
252    self.constant = constant
253
254  @property
255  def name(self):
256    return self.constant.name
257
258
259class EnumValue(NamedValue):
260  def __init__(self, module, enum, field):
261    NamedValue.__init__(self, module, enum.parent_kind, field.mojom_name)
262    self.field = field
263    self.enum = enum
264
265  def GetSpec(self):
266    return (self.module.mojom_namespace + '.' +
267        (self.parent_kind and (self.parent_kind.mojom_name + '.') or "") +
268        self.enum.mojom_name + '.' + self.mojom_name)
269
270  @property
271  def name(self):
272    return self.field.name
273
274
275class Constant(object):
276  def __init__(self, mojom_name=None, kind=None, value=None, parent_kind=None):
277    self.mojom_name = mojom_name
278    self.kind = kind
279    self.value = value
280    self.parent_kind = parent_kind
281
282  def Stylize(self, stylizer):
283    self.name = stylizer.StylizeConstant(self.mojom_name)
284
285
286class Field(object):
287  def __init__(self, mojom_name=None, kind=None, ordinal=None, default=None,
288               attributes=None):
289    if self.__class__.__name__ == 'Field':
290      raise Exception()
291    self.mojom_name = mojom_name
292    self.kind = kind
293    self.ordinal = ordinal
294    self.default = default
295    self.attributes = attributes
296
297  def Repr(self, as_ref=True):
298    # Fields are only referenced by objects which define them and thus
299    # they are always displayed as non-references.
300    return GenericRepr(self, {'mojom_name': False, 'kind': True})
301
302  def Stylize(self, stylizer):
303    self.name = stylizer.StylizeField(self.mojom_name)
304
305  @property
306  def min_version(self):
307    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
308        if self.attributes else None
309
310
311class StructField(Field): pass
312
313
314class UnionField(Field): pass
315
316
317class Struct(ReferenceKind):
318  """A struct with typed fields.
319
320  Attributes:
321    mojom_name: {str} The name of the struct type as defined in mojom.
322    name: {str} The stylized name.
323    native_only: {bool} Does the struct have a body (i.e. any fields) or is it
324        purely a native struct.
325    custom_serializer: {bool} Should we generate a serializer for the struct or
326        will one be provided by non-generated code.
327    fields: {List[StructField]} The members of the struct.
328    enums: {List[Enum]} The enums defined in the struct scope.
329    constants: {List[Constant]} The constants defined in the struct scope.
330    attributes: {dict} Additional information about the struct, such as
331        if it's a native struct.
332  """
333
334  ReferenceKind.AddSharedProperty('mojom_name')
335  ReferenceKind.AddSharedProperty('name')
336  ReferenceKind.AddSharedProperty('native_only')
337  ReferenceKind.AddSharedProperty('custom_serializer')
338  ReferenceKind.AddSharedProperty('fields')
339  ReferenceKind.AddSharedProperty('enums')
340  ReferenceKind.AddSharedProperty('constants')
341  ReferenceKind.AddSharedProperty('attributes')
342
343  def __init__(self, mojom_name=None, module=None, attributes=None):
344    if mojom_name is not None:
345      spec = 'x:' + mojom_name
346    else:
347      spec = None
348    ReferenceKind.__init__(self, spec, False, module)
349    self.mojom_name = mojom_name
350    self.native_only = False
351    self.custom_serializer = False
352    self.fields = []
353    self.enums = []
354    self.constants = []
355    self.attributes = attributes
356
357  def Repr(self, as_ref=True):
358    if as_ref:
359      return '<%s mojom_name=%r module=%s>' % (
360          self.__class__.__name__, self.mojom_name,
361          Repr(self.module, as_ref=True))
362    else:
363      return GenericRepr(self,
364          {'mojom_name': False, 'fields': False, 'module': True})
365
366  def AddField(self, mojom_name, kind, ordinal=None, default=None,
367               attributes=None):
368    field = StructField(mojom_name, kind, ordinal, default, attributes)
369    self.fields.append(field)
370    return field
371
372  def Stylize(self, stylizer):
373    self.name = stylizer.StylizeStruct(self.mojom_name)
374    for field in self.fields:
375      field.Stylize(stylizer)
376    for enum in self.enums:
377      enum.Stylize(stylizer)
378    for constant in self.constants:
379      constant.Stylize(stylizer)
380
381
382class Union(ReferenceKind):
383  """A union of several kinds.
384
385  Attributes:
386    mojom_name: {str} The name of the union type as defined in mojom.
387    name: {str} The stylized name.
388    fields: {List[UnionField]} The members of the union.
389    attributes: {dict} Additional information about the union, such as
390        which Java class name to use to represent it in the generated
391        bindings.
392  """
393  ReferenceKind.AddSharedProperty('mojom_name')
394  ReferenceKind.AddSharedProperty('name')
395  ReferenceKind.AddSharedProperty('fields')
396  ReferenceKind.AddSharedProperty('attributes')
397
398  def __init__(self, mojom_name=None, module=None, attributes=None):
399    if mojom_name is not None:
400      spec = 'x:' + mojom_name
401    else:
402      spec = None
403    ReferenceKind.__init__(self, spec, False, module)
404    self.mojom_name = mojom_name
405    self.fields = []
406    self.attributes = attributes
407
408  def Repr(self, as_ref=True):
409    if as_ref:
410      return '<%s spec=%r is_nullable=%r fields=%s>' % (
411          self.__class__.__name__, self.spec, self.is_nullable,
412          Repr(self.fields))
413    else:
414      return GenericRepr(self, {'fields': True, 'is_nullable': False})
415
416  def AddField(self, mojom_name, kind, ordinal=None, attributes=None):
417    field = UnionField(mojom_name, kind, ordinal, None, attributes)
418    self.fields.append(field)
419    return field
420
421  def Stylize(self, stylizer):
422    self.name = stylizer.StylizeUnion(self.mojom_name)
423    for field in self.fields:
424      field.Stylize(stylizer)
425
426
427class Array(ReferenceKind):
428  """An array.
429
430  Attributes:
431    kind: {Kind} The type of the elements. May be None.
432    length: The number of elements. None if unknown.
433  """
434
435  ReferenceKind.AddSharedProperty('kind')
436  ReferenceKind.AddSharedProperty('length')
437
438  def __init__(self, kind=None, length=None):
439    if kind is not None:
440      if length is not None:
441        spec = 'a%d:%s' % (length, kind.spec)
442      else:
443        spec = 'a:%s' % kind.spec
444
445      ReferenceKind.__init__(self, spec)
446    else:
447      ReferenceKind.__init__(self)
448    self.kind = kind
449    self.length = length
450
451  def Repr(self, as_ref=True):
452    if as_ref:
453      return '<%s spec=%r is_nullable=%r kind=%s length=%r>' % (
454          self.__class__.__name__, self.spec, self.is_nullable, Repr(self.kind),
455          self.length)
456    else:
457      return GenericRepr(self, {'kind': True, 'length': False,
458                                'is_nullable': False})
459
460
461class Map(ReferenceKind):
462  """A map.
463
464  Attributes:
465    key_kind: {Kind} The type of the keys. May be None.
466    value_kind: {Kind} The type of the elements. May be None.
467  """
468  ReferenceKind.AddSharedProperty('key_kind')
469  ReferenceKind.AddSharedProperty('value_kind')
470
471  def __init__(self, key_kind=None, value_kind=None):
472    if (key_kind is not None and value_kind is not None):
473      ReferenceKind.__init__(self,
474                             'm[' + key_kind.spec + '][' + value_kind.spec +
475                             ']')
476      if IsNullableKind(key_kind):
477        raise Exception("Nullable kinds cannot be keys in maps.")
478      if IsAnyHandleKind(key_kind):
479        raise Exception("Handles cannot be keys in maps.")
480      if IsAnyInterfaceKind(key_kind):
481        raise Exception("Interfaces cannot be keys in maps.")
482      if IsArrayKind(key_kind):
483        raise Exception("Arrays cannot be keys in maps.")
484    else:
485      ReferenceKind.__init__(self)
486
487    self.key_kind = key_kind
488    self.value_kind = value_kind
489
490  def Repr(self, as_ref=True):
491    if as_ref:
492      return '<%s spec=%r is_nullable=%r key_kind=%s value_kind=%s>' % (
493          self.__class__.__name__, self.spec, self.is_nullable,
494          Repr(self.key_kind), Repr(self.value_kind))
495    else:
496      return GenericRepr(self, {'key_kind': True, 'value_kind': True})
497
498
499class InterfaceRequest(ReferenceKind):
500  ReferenceKind.AddSharedProperty('kind')
501
502  def __init__(self, kind=None):
503    if kind is not None:
504      if not isinstance(kind, Interface):
505        raise Exception(
506            "Interface request requires %r to be an interface." % kind.spec)
507      ReferenceKind.__init__(self, 'r:' + kind.spec)
508    else:
509      ReferenceKind.__init__(self)
510    self.kind = kind
511
512
513class AssociatedInterfaceRequest(ReferenceKind):
514  ReferenceKind.AddSharedProperty('kind')
515
516  def __init__(self, kind=None):
517    if kind is not None:
518      if not isinstance(kind, InterfaceRequest):
519        raise Exception(
520            "Associated interface request requires %r to be an interface "
521            "request." % kind.spec)
522      assert not kind.is_nullable
523      ReferenceKind.__init__(self, 'asso:' + kind.spec)
524    else:
525      ReferenceKind.__init__(self)
526    self.kind = kind.kind if kind is not None else None
527
528
529class Parameter(object):
530  def __init__(self, mojom_name=None, kind=None, ordinal=None, default=None,
531               attributes=None):
532    self.mojom_name = mojom_name
533    self.ordinal = ordinal
534    self.kind = kind
535    self.default = default
536    self.attributes = attributes
537
538  def Repr(self, as_ref=True):
539    return '<%s mojom_name=%r kind=%s>' % (
540        self.__class__.__name__, self.mojom_name, self.kind.Repr(as_ref=True))
541
542  def Stylize(self, stylizer):
543    self.name = stylizer.StylizeParameter(self.mojom_name)
544
545  @property
546  def min_version(self):
547    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
548        if self.attributes else None
549
550
551class Method(object):
552  def __init__(self, interface, mojom_name, ordinal=None, attributes=None):
553    self.interface = interface
554    self.mojom_name = mojom_name
555    self.ordinal = ordinal
556    self.parameters = []
557    self.param_struct = None
558    self.response_parameters = None
559    self.response_param_struct = None
560    self.attributes = attributes
561
562  def Repr(self, as_ref=True):
563    if as_ref:
564      return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
565    else:
566      return GenericRepr(self, {'mojom_name': False, 'parameters': True,
567                                'response_parameters': True})
568
569  def AddParameter(self, mojom_name, kind, ordinal=None, default=None,
570                   attributes=None):
571    parameter = Parameter(mojom_name, kind, ordinal, default, attributes)
572    self.parameters.append(parameter)
573    return parameter
574
575  def AddResponseParameter(self, mojom_name, kind, ordinal=None, default=None,
576                           attributes=None):
577    if self.response_parameters == None:
578      self.response_parameters = []
579    parameter = Parameter(mojom_name, kind, ordinal, default, attributes)
580    self.response_parameters.append(parameter)
581    return parameter
582
583  def Stylize(self, stylizer):
584    self.name = stylizer.StylizeMethod(self.mojom_name)
585    for param in self.parameters:
586      param.Stylize(stylizer)
587    if self.response_parameters is not None:
588      for param in self.response_parameters:
589        param.Stylize(stylizer)
590
591    if self.param_struct:
592      self.param_struct.Stylize(stylizer)
593    if self.response_param_struct:
594      self.response_param_struct.Stylize(stylizer)
595
596  @property
597  def min_version(self):
598    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
599        if self.attributes else None
600
601  @property
602  def sync(self):
603    return self.attributes.get(ATTRIBUTE_SYNC) \
604        if self.attributes else None
605
606
607class Interface(ReferenceKind):
608  ReferenceKind.AddSharedProperty('mojom_name')
609  ReferenceKind.AddSharedProperty('name')
610  ReferenceKind.AddSharedProperty('methods')
611  ReferenceKind.AddSharedProperty('enums')
612  ReferenceKind.AddSharedProperty('constants')
613  ReferenceKind.AddSharedProperty('attributes')
614
615  def __init__(self, mojom_name=None, module=None, attributes=None):
616    if mojom_name is not None:
617      spec = 'x:' + mojom_name
618    else:
619      spec = None
620    ReferenceKind.__init__(self, spec, False, module)
621    self.mojom_name = mojom_name
622    self.methods = []
623    self.enums = []
624    self.constants = []
625    self.attributes = attributes
626
627  def Repr(self, as_ref=True):
628    if as_ref:
629      return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
630    else:
631      return GenericRepr(self, {'mojom_name': False, 'attributes': False,
632                                'methods': False})
633
634  def AddMethod(self, mojom_name, ordinal=None, attributes=None):
635    method = Method(self, mojom_name, ordinal, attributes)
636    self.methods.append(method)
637    return method
638
639  def Stylize(self, stylizer):
640    self.name = stylizer.StylizeInterface(self.mojom_name)
641    for method in self.methods:
642      method.Stylize(stylizer)
643    for enum in self.enums:
644      enum.Stylize(stylizer)
645    for constant in self.constants:
646      constant.Stylize(stylizer)
647
648  @property
649  def uuid(self):
650    uuid_str = self.attributes.get(ATTRIBUTE_UUID) if self.attributes else None
651    if uuid_str is None:
652      return None
653
654    try:
655      u = UUID(uuid_str)
656    except:
657      raise ValueError('Invalid format for Uuid attribute on interface {}. '
658                       'Expected standard RFC 4122 string representation of '
659                       'a UUID.'.format(self.mojom_name))
660    return (int(u.hex[:16], 16), int(u.hex[16:], 16))
661
662
663class AssociatedInterface(ReferenceKind):
664  ReferenceKind.AddSharedProperty('kind')
665
666  def __init__(self, kind=None):
667    if kind is not None:
668      if not isinstance(kind, Interface):
669        raise Exception(
670            "Associated interface requires %r to be an interface." % kind.spec)
671      assert not kind.is_nullable
672      ReferenceKind.__init__(self, 'asso:' + kind.spec)
673    else:
674      ReferenceKind.__init__(self)
675    self.kind = kind
676
677
678class EnumField(object):
679  def __init__(self, mojom_name=None, value=None, attributes=None,
680               numeric_value=None):
681    self.mojom_name = mojom_name
682    self.value = value
683    self.attributes = attributes
684    self.numeric_value = numeric_value
685
686  def Stylize(self, stylizer):
687    self.name = stylizer.StylizeEnumField(self.mojom_name)
688
689  @property
690  def min_version(self):
691    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
692        if self.attributes else None
693
694
695class Enum(Kind):
696  def __init__(self, mojom_name=None, module=None, attributes=None):
697    self.mojom_name = mojom_name
698    self.native_only = False
699    if mojom_name is not None:
700      spec = 'x:' + mojom_name
701    else:
702      spec = None
703    Kind.__init__(self, spec, module)
704    self.fields = []
705    self.attributes = attributes
706    self.min_value = None
707    self.max_value = None
708
709  def Repr(self, as_ref=True):
710    if as_ref:
711      return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
712    else:
713      return GenericRepr(self, {'mojom_name': False, 'fields': False})
714
715  def Stylize(self, stylizer):
716    self.name = stylizer.StylizeEnum(self.mojom_name)
717    for field in self.fields:
718      field.Stylize(stylizer)
719
720  @property
721  def extensible(self):
722    return self.attributes.get(ATTRIBUTE_EXTENSIBLE, False) \
723        if self.attributes else False
724
725
726class Module(object):
727  def __init__(self, path=None, mojom_namespace=None,
728               attributes=None):
729    self.path = path
730    self.mojom_namespace = mojom_namespace
731    self.structs = []
732    self.unions = []
733    self.interfaces = []
734    self.enums = []
735    self.constants = []
736    self.kinds = {}
737    self.attributes = attributes
738    self.imports = []
739
740  def __repr__(self):
741    # Gives us a decent __repr__ for modules.
742    return self.Repr()
743
744  def Repr(self, as_ref=True):
745    if as_ref:
746      return '<%s path=%r mojom_namespace=%r>' % (
747          self.__class__.__name__, self.path, self.mojom_namespace)
748    else:
749      return GenericRepr(self, {'path': False, 'mojom_namespace': False,
750                                'attributes': False, 'structs': False,
751                                'interfaces': False, 'unions': False})
752
753  def AddInterface(self, mojom_name, attributes=None):
754    interface = Interface(mojom_name, self, attributes)
755    self.interfaces.append(interface)
756    return interface
757
758  def AddStruct(self, mojom_name, attributes=None):
759    struct = Struct(mojom_name, self, attributes)
760    self.structs.append(struct)
761    return struct
762
763  def AddUnion(self, mojom_name, attributes=None):
764    union = Union(mojom_name, self, attributes)
765    self.unions.append(union)
766    return union
767
768  def Stylize(self, stylizer):
769    self.namespace = stylizer.StylizeModule(self.mojom_namespace)
770    for struct in self.structs:
771      struct.Stylize(stylizer)
772    for union in self.unions:
773      union.Stylize(stylizer)
774    for interface in self.interfaces:
775      interface.Stylize(stylizer)
776    for enum in self.enums:
777      enum.Stylize(stylizer)
778    for constant in self.constants:
779      constant.Stylize(stylizer)
780
781    for imported_module in self.imports:
782      imported_module.Stylize(stylizer)
783
784
785def IsBoolKind(kind):
786  return kind.spec == BOOL.spec
787
788
789def IsFloatKind(kind):
790  return kind.spec == FLOAT.spec
791
792
793def IsDoubleKind(kind):
794  return kind.spec == DOUBLE.spec
795
796
797def IsIntegralKind(kind):
798  return (kind.spec == BOOL.spec or
799          kind.spec == INT8.spec or
800          kind.spec == INT16.spec or
801          kind.spec == INT32.spec or
802          kind.spec == INT64.spec or
803          kind.spec == UINT8.spec or
804          kind.spec == UINT16.spec or
805          kind.spec == UINT32.spec or
806          kind.spec == UINT64.spec)
807
808
809def IsStringKind(kind):
810  return kind.spec == STRING.spec or kind.spec == NULLABLE_STRING.spec
811
812
813def IsGenericHandleKind(kind):
814  return kind.spec == HANDLE.spec or kind.spec == NULLABLE_HANDLE.spec
815
816
817def IsDataPipeConsumerKind(kind):
818  return kind.spec == DCPIPE.spec or kind.spec == NULLABLE_DCPIPE.spec
819
820
821def IsDataPipeProducerKind(kind):
822  return kind.spec == DPPIPE.spec or kind.spec == NULLABLE_DPPIPE.spec
823
824
825def IsMessagePipeKind(kind):
826  return kind.spec == MSGPIPE.spec or kind.spec == NULLABLE_MSGPIPE.spec
827
828
829def IsSharedBufferKind(kind):
830  return (kind.spec == SHAREDBUFFER.spec or
831          kind.spec == NULLABLE_SHAREDBUFFER.spec)
832
833
834def IsStructKind(kind):
835  return isinstance(kind, Struct)
836
837
838def IsUnionKind(kind):
839  return isinstance(kind, Union)
840
841
842def IsArrayKind(kind):
843  return isinstance(kind, Array)
844
845
846def IsInterfaceKind(kind):
847  return isinstance(kind, Interface)
848
849
850def IsAssociatedInterfaceKind(kind):
851  return isinstance(kind, AssociatedInterface)
852
853
854def IsInterfaceRequestKind(kind):
855  return isinstance(kind, InterfaceRequest)
856
857
858def IsAssociatedInterfaceRequestKind(kind):
859  return isinstance(kind, AssociatedInterfaceRequest)
860
861
862def IsEnumKind(kind):
863  return isinstance(kind, Enum)
864
865
866def IsReferenceKind(kind):
867  return isinstance(kind, ReferenceKind)
868
869
870def IsNullableKind(kind):
871  return IsReferenceKind(kind) and kind.is_nullable
872
873
874def IsMapKind(kind):
875  return isinstance(kind, Map)
876
877
878def IsObjectKind(kind):
879  return IsPointerKind(kind) or IsUnionKind(kind)
880
881
882def IsPointerKind(kind):
883  return (IsStructKind(kind) or IsArrayKind(kind) or IsStringKind(kind) or
884          IsMapKind(kind))
885
886
887# Please note that it doesn't include any interface kind.
888def IsAnyHandleKind(kind):
889  return (IsGenericHandleKind(kind) or
890          IsDataPipeConsumerKind(kind) or
891          IsDataPipeProducerKind(kind) or
892          IsMessagePipeKind(kind) or
893          IsSharedBufferKind(kind))
894
895
896def IsAnyInterfaceKind(kind):
897  return (IsInterfaceKind(kind) or IsInterfaceRequestKind(kind) or
898          IsAssociatedKind(kind))
899
900
901def IsAnyHandleOrInterfaceKind(kind):
902  return IsAnyHandleKind(kind) or IsAnyInterfaceKind(kind)
903
904
905def IsAssociatedKind(kind):
906  return (IsAssociatedInterfaceKind(kind) or
907          IsAssociatedInterfaceRequestKind(kind))
908
909
910def HasCallbacks(interface):
911  for method in interface.methods:
912    if method.response_parameters != None:
913      return True
914  return False
915
916
917# Finds out whether an interface passes associated interfaces and associated
918# interface requests.
919def PassesAssociatedKinds(interface):
920  visited_kinds = set()
921  for method in interface.methods:
922    if MethodPassesAssociatedKinds(method, visited_kinds):
923      return True
924  return False
925
926
927def _AnyMethodParameterRecursive(method, predicate, visited_kinds=None):
928  def _HasProperty(kind):
929    if kind in visited_kinds:
930      # No need to examine the kind again.
931      return False
932    visited_kinds.add(kind)
933    if predicate(kind):
934      return True
935    if IsArrayKind(kind):
936      return _HasProperty(kind.kind)
937    if IsStructKind(kind) or IsUnionKind(kind):
938      for field in kind.fields:
939        if _HasProperty(field.kind):
940          return True
941    if IsMapKind(kind):
942      if  _HasProperty(kind.key_kind) or _HasProperty(kind.value_kind):
943        return True
944    return False
945
946  if visited_kinds is None:
947    visited_kinds = set()
948
949  for param in method.parameters:
950    if _HasProperty(param.kind):
951      return True
952  if method.response_parameters != None:
953    for param in method.response_parameters:
954      if _HasProperty(param.kind):
955        return True
956  return False
957
958
959# Finds out whether a method passes associated interfaces and associated
960# interface requests.
961def MethodPassesAssociatedKinds(method, visited_kinds=None):
962  return _AnyMethodParameterRecursive(method, IsAssociatedKind,
963                                      visited_kinds=visited_kinds)
964
965
966# Determines whether a method passes interfaces.
967def MethodPassesInterfaces(method):
968  return _AnyMethodParameterRecursive(method, IsInterfaceKind)
969
970
971def HasSyncMethods(interface):
972  for method in interface.methods:
973    if method.sync:
974      return True
975  return False
976
977
978def ContainsHandlesOrInterfaces(kind):
979  """Check if the kind contains any handles.
980
981  This check is recursive so it checks all struct fields, containers elements,
982  etc.
983
984  Args:
985    struct: {Kind} The kind to check.
986
987  Returns:
988    {bool}: True if the kind contains handles.
989  """
990  # We remember the types we already checked to avoid infinite recursion when
991  # checking recursive (or mutually recursive) types:
992  checked = set()
993  def Check(kind):
994    if kind.spec in checked:
995      return False
996    checked.add(kind.spec)
997    if IsStructKind(kind):
998      return any(Check(field.kind) for field in kind.fields)
999    elif IsUnionKind(kind):
1000      return any(Check(field.kind) for field in kind.fields)
1001    elif IsAnyHandleKind(kind):
1002      return True
1003    elif IsAnyInterfaceKind(kind):
1004      return True
1005    elif IsArrayKind(kind):
1006      return Check(kind.kind)
1007    elif IsMapKind(kind):
1008      return Check(kind.key_kind) or Check(kind.value_kind)
1009    else:
1010      return False
1011  return Check(kind)
1012