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