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