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