summaryrefslogtreecommitdiff
path: root/utils/ipc/mojo/public/tools/mojom/mojom/generate/module.py
diff options
context:
space:
mode:
Diffstat (limited to 'utils/ipc/mojo/public/tools/mojom/mojom/generate/module.py')
-rw-r--r--utils/ipc/mojo/public/tools/mojom/mojom/generate/module.py787
1 files changed, 544 insertions, 243 deletions
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/module.py b/utils/ipc/mojo/public/tools/mojom/mojom/generate/module.py
index 9bdb28e0..ca71059d 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/module.py
+++ b/utils/ipc/mojo/public/tools/mojom/mojom/generate/module.py
@@ -1,4 +1,4 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2013 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -12,15 +12,14 @@
# method = interface.AddMethod('Tat', 0)
# method.AddParameter('baz', 0, mojom.INT32)
-import sys
-if sys.version_info.major == 2:
- import cPickle as pickle
-else:
- import pickle
+import pickle
+from collections import OrderedDict
from uuid import UUID
+# pylint: disable=raise-missing-from
-class BackwardCompatibilityChecker(object):
+
+class BackwardCompatibilityChecker:
"""Used for memoization while recursively checking two type definitions for
backward-compatibility."""
@@ -64,23 +63,20 @@ def Repr(obj, as_ref=True):
return obj.Repr(as_ref=as_ref)
# Since we cannot implement Repr for existing container types, we
# handle them here.
- elif isinstance(obj, list):
+ if isinstance(obj, list):
if not obj:
return '[]'
- else:
- return ('[\n%s\n]' % (',\n'.join(
- ' %s' % Repr(elem, as_ref).replace('\n', '\n ')
- for elem in obj)))
- elif isinstance(obj, dict):
+ return ('[\n%s\n]' %
+ (',\n'.join(' %s' % Repr(elem, as_ref).replace('\n', '\n ')
+ for elem in obj)))
+ if isinstance(obj, dict):
if not obj:
return '{}'
- else:
- return ('{\n%s\n}' % (',\n'.join(
- ' %s: %s' % (Repr(key, as_ref).replace('\n', '\n '),
- Repr(val, as_ref).replace('\n', '\n '))
- for key, val in obj.items())))
- else:
- return repr(obj)
+ return ('{\n%s\n}' % (',\n'.join(' %s: %s' %
+ (Repr(key, as_ref).replace('\n', '\n '),
+ Repr(val, as_ref).replace('\n', '\n '))
+ for key, val in obj.items())))
+ return repr(obj)
def GenericRepr(obj, names):
@@ -104,7 +100,7 @@ def GenericRepr(obj, names):
ReprIndent(name, as_ref) for (name, as_ref) in names.items()))
-class Kind(object):
+class Kind:
"""Kind represents a type (e.g. int8, string).
Attributes:
@@ -112,16 +108,43 @@ class Kind(object):
module: {Module} The defining module. Set to None for built-in types.
parent_kind: The enclosing type. For example, an enum defined
inside an interface has that interface as its parent. May be None.
+ is_nullable: True if the type is nullable.
"""
- def __init__(self, spec=None, module=None):
+ def __init__(self, spec=None, is_nullable=False, module=None):
self.spec = spec
self.module = module
self.parent_kind = None
+ self.is_nullable = is_nullable
+ self.shared_definition = {}
+
+ @classmethod
+ def AddSharedProperty(cls, name):
+ """Adds a property |name| to |cls|, which accesses the corresponding item in
+ |shared_definition|.
+
+ The reason of adding such indirection is to enable sharing definition
+ between a reference kind and its nullable variation. For example:
+ a = Struct('test_struct_1')
+ b = a.MakeNullableKind()
+ a.name = 'test_struct_2'
+ print(b.name) # Outputs 'test_struct_2'.
+ """
+ def Get(self):
+ try:
+ return self.shared_definition[name]
+ except KeyError: # Must raise AttributeError if property doesn't exist.
+ raise AttributeError
+
+ def Set(self, value):
+ self.shared_definition[name] = value
+
+ setattr(cls, name, property(Get, Set))
def Repr(self, as_ref=True):
# pylint: disable=unused-argument
- return '<%s spec=%r>' % (self.__class__.__name__, self.spec)
+ return '<%s spec=%r is_nullable=%r>' % (self.__class__.__name__, self.spec,
+ self.is_nullable)
def __repr__(self):
# Gives us a decent __repr__ for all kinds.
@@ -130,7 +153,8 @@ class Kind(object):
def __eq__(self, rhs):
# pylint: disable=unidiomatic-typecheck
return (type(self) == type(rhs)
- and (self.spec, self.parent_kind) == (rhs.spec, rhs.parent_kind))
+ and (self.spec, self.parent_kind, self.is_nullable)
+ == (rhs.spec, rhs.parent_kind, rhs.is_nullable))
def __hash__(self):
# TODO(crbug.com/1060471): Remove this and other __hash__ methods on Kind
@@ -138,32 +162,113 @@ class Kind(object):
# some primitive Kinds as dict keys. The default hash (object identity)
# breaks these dicts when a pickled Module instance is unpickled and used
# during a subsequent run of the parser.
- return hash((self.spec, self.parent_kind))
+ return hash((self.spec, self.parent_kind, self.is_nullable))
# pylint: disable=unused-argument
def IsBackwardCompatible(self, rhs, checker):
return self == rhs
+class ValueKind(Kind):
+ """ValueKind represents values that aren't reference kinds.
+
+ The primary difference is the wire representation for nullable value kinds
+ still reserves space for the value type itself, even if that value itself
+ is logically null.
+ """
+ def __init__(self, spec=None, is_nullable=False, module=None):
+ assert spec is None or is_nullable == spec.startswith('?')
+ Kind.__init__(self, spec, is_nullable, module)
+
+ def MakeNullableKind(self):
+ assert not self.is_nullable
+
+ if self == BOOL:
+ return NULLABLE_BOOL
+ if self == INT8:
+ return NULLABLE_INT8
+ if self == INT16:
+ return NULLABLE_INT16
+ if self == INT32:
+ return NULLABLE_INT32
+ if self == INT64:
+ return NULLABLE_INT64
+ if self == UINT8:
+ return NULLABLE_UINT8
+ if self == UINT16:
+ return NULLABLE_UINT16
+ if self == UINT32:
+ return NULLABLE_UINT32
+ if self == UINT64:
+ return NULLABLE_UINT64
+ if self == FLOAT:
+ return NULLABLE_FLOAT
+ if self == DOUBLE:
+ return NULLABLE_DOUBLE
+
+ nullable_kind = type(self)()
+ nullable_kind.shared_definition = self.shared_definition
+ if self.spec is not None:
+ nullable_kind.spec = '?' + self.spec
+ nullable_kind.is_nullable = True
+ nullable_kind.parent_kind = self.parent_kind
+ nullable_kind.module = self.module
+
+ return nullable_kind
+
+ def MakeUnnullableKind(self):
+ assert self.is_nullable
+
+ if self == NULLABLE_BOOL:
+ return BOOL
+ if self == NULLABLE_INT8:
+ return INT8
+ if self == NULLABLE_INT16:
+ return INT16
+ if self == NULLABLE_INT32:
+ return INT32
+ if self == NULLABLE_INT64:
+ return INT64
+ if self == NULLABLE_UINT8:
+ return UINT8
+ if self == NULLABLE_UINT16:
+ return UINT16
+ if self == NULLABLE_UINT32:
+ return UINT32
+ if self == NULLABLE_UINT64:
+ return UINT64
+ if self == NULLABLE_FLOAT:
+ return FLOAT
+ if self == NULLABLE_DOUBLE:
+ return DOUBLE
+
+ nullable_kind = type(self)()
+ nullable_kind.shared_definition = self.shared_definition
+ if self.spec is not None:
+ nullable_kind.spec = self.spec[1:]
+ nullable_kind.is_nullable = False
+ nullable_kind.parent_kind = self.parent_kind
+ nullable_kind.module = self.module
+
+ return nullable_kind
+
+ def __eq__(self, rhs):
+ return (isinstance(rhs, ValueKind) and super().__eq__(rhs))
+
+ def __hash__(self): # pylint: disable=useless-super-delegation
+ return super().__hash__()
+
+
class ReferenceKind(Kind):
"""ReferenceKind represents pointer and handle types.
A type is nullable if null (for pointer types) or invalid handle (for handle
types) is a legal value for the type.
-
- Attributes:
- is_nullable: True if the type is nullable.
"""
def __init__(self, spec=None, is_nullable=False, module=None):
assert spec is None or is_nullable == spec.startswith('?')
- Kind.__init__(self, spec, module)
- self.is_nullable = is_nullable
- self.shared_definition = {}
-
- def Repr(self, as_ref=True):
- return '<%s spec=%r is_nullable=%r>' % (self.__class__.__name__, self.spec,
- self.is_nullable)
+ Kind.__init__(self, spec, is_nullable, module)
def MakeNullableKind(self):
assert not self.is_nullable
@@ -193,55 +298,65 @@ class ReferenceKind(Kind):
return nullable_kind
- @classmethod
- def AddSharedProperty(cls, name):
- """Adds a property |name| to |cls|, which accesses the corresponding item in
- |shared_definition|.
-
- The reason of adding such indirection is to enable sharing definition
- between a reference kind and its nullable variation. For example:
- a = Struct('test_struct_1')
- b = a.MakeNullableKind()
- a.name = 'test_struct_2'
- print(b.name) # Outputs 'test_struct_2'.
- """
-
- def Get(self):
- try:
- return self.shared_definition[name]
- except KeyError: # Must raise AttributeError if property doesn't exist.
- raise AttributeError
-
- def Set(self, value):
- self.shared_definition[name] = value
+ def MakeUnnullableKind(self):
+ assert self.is_nullable
+
+ if self == NULLABLE_STRING:
+ return STRING
+ if self == NULLABLE_HANDLE:
+ return HANDLE
+ if self == NULLABLE_DCPIPE:
+ return DCPIPE
+ if self == NULLABLE_DPPIPE:
+ return DPPIPE
+ if self == NULLABLE_MSGPIPE:
+ return MSGPIPE
+ if self == NULLABLE_SHAREDBUFFER:
+ return SHAREDBUFFER
+ if self == NULLABLE_PLATFORMHANDLE:
+ return PLATFORMHANDLE
+
+ unnullable_kind = type(self)()
+ unnullable_kind.shared_definition = self.shared_definition
+ if self.spec is not None:
+ assert self.spec[0] == '?'
+ unnullable_kind.spec = self.spec[1:]
+ unnullable_kind.is_nullable = False
+ unnullable_kind.parent_kind = self.parent_kind
+ unnullable_kind.module = self.module
- setattr(cls, name, property(Get, Set))
+ return unnullable_kind
def __eq__(self, rhs):
- return (isinstance(rhs, ReferenceKind)
- and super(ReferenceKind, self).__eq__(rhs)
- and self.is_nullable == rhs.is_nullable)
+ return (isinstance(rhs, ReferenceKind) and super().__eq__(rhs))
- def __hash__(self):
- return hash((super(ReferenceKind, self).__hash__(), self.is_nullable))
-
- def IsBackwardCompatible(self, rhs, checker):
- return (super(ReferenceKind, self).IsBackwardCompatible(rhs, checker)
- and self.is_nullable == rhs.is_nullable)
+ def __hash__(self): # pylint: disable=useless-super-delegation
+ return super().__hash__()
# Initialize the set of primitive types. These can be accessed by clients.
-BOOL = Kind('b')
-INT8 = Kind('i8')
-INT16 = Kind('i16')
-INT32 = Kind('i32')
-INT64 = Kind('i64')
-UINT8 = Kind('u8')
-UINT16 = Kind('u16')
-UINT32 = Kind('u32')
-UINT64 = Kind('u64')
-FLOAT = Kind('f')
-DOUBLE = Kind('d')
+BOOL = ValueKind('b')
+INT8 = ValueKind('i8')
+INT16 = ValueKind('i16')
+INT32 = ValueKind('i32')
+INT64 = ValueKind('i64')
+UINT8 = ValueKind('u8')
+UINT16 = ValueKind('u16')
+UINT32 = ValueKind('u32')
+UINT64 = ValueKind('u64')
+FLOAT = ValueKind('f')
+DOUBLE = ValueKind('d')
+NULLABLE_BOOL = ValueKind('?b', True)
+NULLABLE_INT8 = ValueKind('?i8', True)
+NULLABLE_INT16 = ValueKind('?i16', True)
+NULLABLE_INT32 = ValueKind('?i32', True)
+NULLABLE_INT64 = ValueKind('?i64', True)
+NULLABLE_UINT8 = ValueKind('?u8', True)
+NULLABLE_UINT16 = ValueKind('?u16', True)
+NULLABLE_UINT32 = ValueKind('?u32', True)
+NULLABLE_UINT64 = ValueKind('?u64', True)
+NULLABLE_FLOAT = ValueKind('?f', True)
+NULLABLE_DOUBLE = ValueKind('?d', True)
STRING = ReferenceKind('s')
HANDLE = ReferenceKind('h')
DCPIPE = ReferenceKind('h:d:c')
@@ -270,6 +385,17 @@ PRIMITIVES = (
UINT64,
FLOAT,
DOUBLE,
+ NULLABLE_BOOL,
+ NULLABLE_INT8,
+ NULLABLE_INT16,
+ NULLABLE_INT32,
+ NULLABLE_INT64,
+ NULLABLE_UINT8,
+ NULLABLE_UINT16,
+ NULLABLE_UINT32,
+ NULLABLE_UINT64,
+ NULLABLE_FLOAT,
+ NULLABLE_DOUBLE,
STRING,
HANDLE,
DCPIPE,
@@ -291,12 +417,17 @@ ATTRIBUTE_DEFAULT = 'Default'
ATTRIBUTE_EXTENSIBLE = 'Extensible'
ATTRIBUTE_NO_INTERRUPT = 'NoInterrupt'
ATTRIBUTE_STABLE = 'Stable'
+ATTRIBUTE_SUPPORTS_URGENT = 'SupportsUrgent'
ATTRIBUTE_SYNC = 'Sync'
ATTRIBUTE_UNLIMITED_SIZE = 'UnlimitedSize'
ATTRIBUTE_UUID = 'Uuid'
+ATTRIBUTE_SERVICE_SANDBOX = 'ServiceSandbox'
+ATTRIBUTE_REQUIRE_CONTEXT = 'RequireContext'
+ATTRIBUTE_ALLOWED_CONTEXT = 'AllowedContext'
+ATTRIBUTE_RUNTIME_FEATURE = 'RuntimeFeature'
-class NamedValue(object):
+class NamedValue:
def __init__(self, module, parent_kind, mojom_name):
self.module = module
self.parent_kind = parent_kind
@@ -316,7 +447,7 @@ class NamedValue(object):
return hash((self.parent_kind, self.mojom_name))
-class BuiltinValue(object):
+class BuiltinValue:
def __init__(self, value):
self.value = value
@@ -350,7 +481,7 @@ class EnumValue(NamedValue):
return self.field.name
-class Constant(object):
+class Constant:
def __init__(self, mojom_name=None, kind=None, value=None, parent_kind=None):
self.mojom_name = mojom_name
self.name = None
@@ -368,7 +499,7 @@ class Constant(object):
rhs.parent_kind))
-class Field(object):
+class Field:
def __init__(self,
mojom_name=None,
kind=None,
@@ -414,7 +545,18 @@ class StructField(Field):
class UnionField(Field):
- pass
+ def __init__(self,
+ mojom_name=None,
+ kind=None,
+ ordinal=None,
+ default=None,
+ attributes=None):
+ Field.__init__(self, mojom_name, kind, ordinal, default, attributes)
+
+ @property
+ def is_default(self):
+ return self.attributes.get(ATTRIBUTE_DEFAULT, False) \
+ if self.attributes else False
def _IsFieldBackwardCompatible(new_field, old_field, checker):
@@ -424,6 +566,38 @@ def _IsFieldBackwardCompatible(new_field, old_field, checker):
return checker.IsBackwardCompatible(new_field.kind, old_field.kind)
+class Feature(ReferenceKind):
+ """A runtime enabled feature defined from mojom.
+
+ Attributes:
+ mojom_name: {str} The name of the feature type as defined in mojom.
+ name: {str} The stylized name. (Note: not the "name" used by FeatureList.)
+ constants: {List[Constant]} The constants defined in the feature scope.
+ attributes: {dict} Additional information about the feature.
+ """
+
+ Kind.AddSharedProperty('mojom_name')
+ Kind.AddSharedProperty('name')
+ Kind.AddSharedProperty('constants')
+ Kind.AddSharedProperty('attributes')
+
+ def __init__(self, mojom_name=None, module=None, attributes=None):
+ if mojom_name is not None:
+ spec = 'x:' + mojom_name
+ else:
+ spec = None
+ ReferenceKind.__init__(self, spec, False, module)
+ self.mojom_name = mojom_name
+ self.name = None
+ self.constants = []
+ self.attributes = attributes
+
+ def Stylize(self, stylizer):
+ self.name = stylizer.StylizeFeature(self.mojom_name)
+ for constant in self.constants:
+ constant.Stylize(stylizer)
+
+
class Struct(ReferenceKind):
"""A struct with typed fields.
@@ -441,14 +615,14 @@ class Struct(ReferenceKind):
if it's a native struct.
"""
- ReferenceKind.AddSharedProperty('mojom_name')
- ReferenceKind.AddSharedProperty('name')
- ReferenceKind.AddSharedProperty('native_only')
- ReferenceKind.AddSharedProperty('custom_serializer')
- ReferenceKind.AddSharedProperty('fields')
- ReferenceKind.AddSharedProperty('enums')
- ReferenceKind.AddSharedProperty('constants')
- ReferenceKind.AddSharedProperty('attributes')
+ Kind.AddSharedProperty('mojom_name')
+ Kind.AddSharedProperty('name')
+ Kind.AddSharedProperty('native_only')
+ Kind.AddSharedProperty('custom_serializer')
+ Kind.AddSharedProperty('fields')
+ Kind.AddSharedProperty('enums')
+ Kind.AddSharedProperty('constants')
+ Kind.AddSharedProperty('attributes')
def __init__(self, mojom_name=None, module=None, attributes=None):
if mojom_name is not None:
@@ -470,12 +644,11 @@ class Struct(ReferenceKind):
return '<%s mojom_name=%r module=%s>' % (self.__class__.__name__,
self.mojom_name,
Repr(self.module, as_ref=True))
- else:
- return GenericRepr(self, {
- 'mojom_name': False,
- 'fields': False,
- 'module': True
- })
+ return GenericRepr(self, {
+ 'mojom_name': False,
+ 'fields': False,
+ 'module': True
+ })
def AddField(self,
mojom_name,
@@ -496,13 +669,13 @@ class Struct(ReferenceKind):
for constant in self.constants:
constant.Stylize(stylizer)
- def IsBackwardCompatible(self, older_struct, checker):
- """This struct is backward-compatible with older_struct if and only if all
- of the following conditions hold:
+ def IsBackwardCompatible(self, rhs, checker):
+ """This struct is backward-compatible with rhs (older_struct) if and only if
+ all of the following conditions hold:
- Any newly added field is tagged with a [MinVersion] attribute specifying
a version number greater than all previously used [MinVersion]
attributes within the struct.
- - All fields present in older_struct remain present in the new struct,
+ - All fields present in rhs remain present in the new struct,
with the same ordinal position, same optional or non-optional status,
same (or backward-compatible) type and where applicable, the same
[MinVersion] attribute value.
@@ -521,7 +694,7 @@ class Struct(ReferenceKind):
return fields_by_ordinal
new_fields = buildOrdinalFieldMap(self)
- old_fields = buildOrdinalFieldMap(older_struct)
+ old_fields = buildOrdinalFieldMap(rhs)
if len(new_fields) < len(old_fields):
# At least one field was removed, which is not OK.
return False
@@ -574,11 +747,18 @@ class Struct(ReferenceKind):
prefix = self.module.GetNamespacePrefix()
return '%s%s' % (prefix, self.mojom_name)
+ def _tuple(self):
+ return (self.mojom_name, self.native_only, self.fields, self.constants,
+ self.attributes)
+
def __eq__(self, rhs):
- return (isinstance(rhs, Struct) and
- (self.mojom_name, self.native_only, self.fields, self.constants,
- self.attributes) == (rhs.mojom_name, rhs.native_only, rhs.fields,
- rhs.constants, rhs.attributes))
+ return isinstance(rhs, Struct) and self._tuple() == rhs._tuple()
+
+ def __lt__(self, rhs):
+ if not isinstance(self, type(rhs)):
+ return str(type(self)) < str(type(rhs))
+
+ return self._tuple() < rhs._tuple()
def __hash__(self):
return id(self)
@@ -595,10 +775,11 @@ class Union(ReferenceKind):
which Java class name to use to represent it in the generated
bindings.
"""
- ReferenceKind.AddSharedProperty('mojom_name')
- ReferenceKind.AddSharedProperty('name')
- ReferenceKind.AddSharedProperty('fields')
- ReferenceKind.AddSharedProperty('attributes')
+ Kind.AddSharedProperty('mojom_name')
+ Kind.AddSharedProperty('name')
+ Kind.AddSharedProperty('fields')
+ Kind.AddSharedProperty('attributes')
+ Kind.AddSharedProperty('default_field')
def __init__(self, mojom_name=None, module=None, attributes=None):
if mojom_name is not None:
@@ -610,14 +791,14 @@ class Union(ReferenceKind):
self.name = None
self.fields = []
self.attributes = attributes
+ self.default_field = None
def Repr(self, as_ref=True):
if as_ref:
return '<%s spec=%r is_nullable=%r fields=%s>' % (
self.__class__.__name__, self.spec, self.is_nullable, Repr(
self.fields))
- else:
- return GenericRepr(self, {'fields': True, 'is_nullable': False})
+ return GenericRepr(self, {'fields': True, 'is_nullable': False})
def AddField(self, mojom_name, kind, ordinal=None, attributes=None):
field = UnionField(mojom_name, kind, ordinal, None, attributes)
@@ -629,13 +810,13 @@ class Union(ReferenceKind):
for field in self.fields:
field.Stylize(stylizer)
- def IsBackwardCompatible(self, older_union, checker):
- """This union is backward-compatible with older_union if and only if all
- of the following conditions hold:
+ def IsBackwardCompatible(self, rhs, checker):
+ """This union is backward-compatible with rhs (older_union) if and only if
+ all of the following conditions hold:
- Any newly added field is tagged with a [MinVersion] attribute specifying
a version number greater than all previously used [MinVersion]
attributes within the union.
- - All fields present in older_union remain present in the new union,
+ - All fields present in rhs remain present in the new union,
with the same ordinal value, same optional or non-optional status,
same (or backward-compatible) type, and where applicable, the same
[MinVersion] attribute value.
@@ -651,7 +832,7 @@ class Union(ReferenceKind):
return fields_by_ordinal
new_fields = buildOrdinalFieldMap(self)
- old_fields = buildOrdinalFieldMap(older_union)
+ old_fields = buildOrdinalFieldMap(rhs)
if len(new_fields) < len(old_fields):
# At least one field was removed, which is not OK.
return False
@@ -678,6 +859,11 @@ class Union(ReferenceKind):
return True
@property
+ def extensible(self):
+ return self.attributes.get(ATTRIBUTE_EXTENSIBLE, False) \
+ if self.attributes else False
+
+ @property
def stable(self):
return self.attributes.get(ATTRIBUTE_STABLE, False) \
if self.attributes else False
@@ -690,10 +876,17 @@ class Union(ReferenceKind):
prefix = self.module.GetNamespacePrefix()
return '%s%s' % (prefix, self.mojom_name)
+ def _tuple(self):
+ return (self.mojom_name, self.fields, self.attributes)
+
def __eq__(self, rhs):
- return (isinstance(rhs, Union) and
- (self.mojom_name, self.fields,
- self.attributes) == (rhs.mojom_name, rhs.fields, rhs.attributes))
+ return isinstance(rhs, Union) and self._tuple() == rhs._tuple()
+
+ def __lt__(self, rhs):
+ if not isinstance(self, type(rhs)):
+ return str(type(self)) < str(type(rhs))
+
+ return self._tuple() < rhs._tuple()
def __hash__(self):
return id(self)
@@ -707,8 +900,8 @@ class Array(ReferenceKind):
length: The number of elements. None if unknown.
"""
- ReferenceKind.AddSharedProperty('kind')
- ReferenceKind.AddSharedProperty('length')
+ Kind.AddSharedProperty('kind')
+ Kind.AddSharedProperty('length')
def __init__(self, kind=None, length=None):
if kind is not None:
@@ -728,12 +921,11 @@ class Array(ReferenceKind):
return '<%s spec=%r is_nullable=%r kind=%s length=%r>' % (
self.__class__.__name__, self.spec, self.is_nullable, Repr(
self.kind), self.length)
- else:
- return GenericRepr(self, {
- 'kind': True,
- 'length': False,
- 'is_nullable': False
- })
+ return GenericRepr(self, {
+ 'kind': True,
+ 'length': False,
+ 'is_nullable': False
+ })
def __eq__(self, rhs):
return (isinstance(rhs, Array)
@@ -754,8 +946,8 @@ class Map(ReferenceKind):
key_kind: {Kind} The type of the keys. May be None.
value_kind: {Kind} The type of the elements. May be None.
"""
- ReferenceKind.AddSharedProperty('key_kind')
- ReferenceKind.AddSharedProperty('value_kind')
+ Kind.AddSharedProperty('key_kind')
+ Kind.AddSharedProperty('value_kind')
def __init__(self, key_kind=None, value_kind=None):
if (key_kind is not None and value_kind is not None):
@@ -780,8 +972,7 @@ class Map(ReferenceKind):
return '<%s spec=%r is_nullable=%r key_kind=%s value_kind=%s>' % (
self.__class__.__name__, self.spec, self.is_nullable,
Repr(self.key_kind), Repr(self.value_kind))
- else:
- return GenericRepr(self, {'key_kind': True, 'value_kind': True})
+ return GenericRepr(self, {'key_kind': True, 'value_kind': True})
def __eq__(self, rhs):
return (isinstance(rhs, Map) and
@@ -797,7 +988,7 @@ class Map(ReferenceKind):
class PendingRemote(ReferenceKind):
- ReferenceKind.AddSharedProperty('kind')
+ Kind.AddSharedProperty('kind')
def __init__(self, kind=None):
if kind is not None:
@@ -822,7 +1013,7 @@ class PendingRemote(ReferenceKind):
class PendingReceiver(ReferenceKind):
- ReferenceKind.AddSharedProperty('kind')
+ Kind.AddSharedProperty('kind')
def __init__(self, kind=None):
if kind is not None:
@@ -847,7 +1038,7 @@ class PendingReceiver(ReferenceKind):
class PendingAssociatedRemote(ReferenceKind):
- ReferenceKind.AddSharedProperty('kind')
+ Kind.AddSharedProperty('kind')
def __init__(self, kind=None):
if kind is not None:
@@ -873,7 +1064,7 @@ class PendingAssociatedRemote(ReferenceKind):
class PendingAssociatedReceiver(ReferenceKind):
- ReferenceKind.AddSharedProperty('kind')
+ Kind.AddSharedProperty('kind')
def __init__(self, kind=None):
if kind is not None:
@@ -899,7 +1090,7 @@ class PendingAssociatedReceiver(ReferenceKind):
class InterfaceRequest(ReferenceKind):
- ReferenceKind.AddSharedProperty('kind')
+ Kind.AddSharedProperty('kind')
def __init__(self, kind=None):
if kind is not None:
@@ -923,7 +1114,7 @@ class InterfaceRequest(ReferenceKind):
class AssociatedInterfaceRequest(ReferenceKind):
- ReferenceKind.AddSharedProperty('kind')
+ Kind.AddSharedProperty('kind')
def __init__(self, kind=None):
if kind is not None:
@@ -949,7 +1140,7 @@ class AssociatedInterfaceRequest(ReferenceKind):
self.kind, rhs.kind)
-class Parameter(object):
+class Parameter:
def __init__(self,
mojom_name=None,
kind=None,
@@ -983,7 +1174,7 @@ class Parameter(object):
rhs.default, rhs.attributes))
-class Method(object):
+class Method:
def __init__(self, interface, mojom_name, ordinal=None, attributes=None):
self.interface = interface
self.mojom_name = mojom_name
@@ -999,12 +1190,11 @@ class Method(object):
def Repr(self, as_ref=True):
if as_ref:
return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
- else:
- return GenericRepr(self, {
- 'mojom_name': False,
- 'parameters': True,
- 'response_parameters': True
- })
+ return GenericRepr(self, {
+ 'mojom_name': False,
+ 'parameters': True,
+ 'response_parameters': True
+ })
def AddParameter(self,
mojom_name,
@@ -1061,21 +1251,49 @@ class Method(object):
return self.attributes.get(ATTRIBUTE_UNLIMITED_SIZE) \
if self.attributes else False
+ @property
+ def allowed_context(self):
+ return self.attributes.get(ATTRIBUTE_ALLOWED_CONTEXT) \
+ if self.attributes else None
+
+ @property
+ def supports_urgent(self):
+ return self.attributes.get(ATTRIBUTE_SUPPORTS_URGENT) \
+ if self.attributes else None
+
+ @property
+ def runtime_feature(self):
+ if not self.attributes:
+ return None
+ runtime_feature = self.attributes.get(ATTRIBUTE_RUNTIME_FEATURE, None)
+ if runtime_feature is None:
+ return None
+ if not isinstance(runtime_feature, Feature):
+ raise Exception("RuntimeFeature attribute on %s must be a feature." %
+ self.name)
+ return runtime_feature
+
+ def _tuple(self):
+ return (self.mojom_name, self.ordinal, self.parameters,
+ self.response_parameters, self.attributes)
+
def __eq__(self, rhs):
- return (isinstance(rhs, Method) and
- (self.mojom_name, self.ordinal, self.parameters,
- self.response_parameters,
- self.attributes) == (rhs.mojom_name, rhs.ordinal, rhs.parameters,
- rhs.response_parameters, rhs.attributes))
+ return isinstance(rhs, Method) and self._tuple() == rhs._tuple()
+
+ def __lt__(self, rhs):
+ if not isinstance(self, type(rhs)):
+ return str(type(self)) < str(type(rhs))
+
+ return self._tuple() < rhs._tuple()
class Interface(ReferenceKind):
- ReferenceKind.AddSharedProperty('mojom_name')
- ReferenceKind.AddSharedProperty('name')
- ReferenceKind.AddSharedProperty('methods')
- ReferenceKind.AddSharedProperty('enums')
- ReferenceKind.AddSharedProperty('constants')
- ReferenceKind.AddSharedProperty('attributes')
+ Kind.AddSharedProperty('mojom_name')
+ Kind.AddSharedProperty('name')
+ Kind.AddSharedProperty('methods')
+ Kind.AddSharedProperty('enums')
+ Kind.AddSharedProperty('constants')
+ Kind.AddSharedProperty('attributes')
def __init__(self, mojom_name=None, module=None, attributes=None):
if mojom_name is not None:
@@ -1093,12 +1311,11 @@ class Interface(ReferenceKind):
def Repr(self, as_ref=True):
if as_ref:
return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
- else:
- return GenericRepr(self, {
- 'mojom_name': False,
- 'attributes': False,
- 'methods': False
- })
+ return GenericRepr(self, {
+ 'mojom_name': False,
+ 'attributes': False,
+ 'methods': False
+ })
def AddMethod(self, mojom_name, ordinal=None, attributes=None):
method = Method(self, mojom_name, ordinal, attributes)
@@ -1114,10 +1331,10 @@ class Interface(ReferenceKind):
for constant in self.constants:
constant.Stylize(stylizer)
- def IsBackwardCompatible(self, older_interface, checker):
- """This interface is backward-compatible with older_interface if and only
- if all of the following conditions hold:
- - All defined methods in older_interface (when identified by ordinal) have
+ def IsBackwardCompatible(self, rhs, checker):
+ """This interface is backward-compatible with rhs (older_interface) if and
+ only if all of the following conditions hold:
+ - All defined methods in rhs (when identified by ordinal) have
backward-compatible definitions in this interface. For each method this
means:
- The parameter list is backward-compatible, according to backward-
@@ -1131,7 +1348,7 @@ class Interface(ReferenceKind):
rules for structs.
- All newly introduced methods in this interface have a [MinVersion]
attribute specifying a version greater than any method in
- older_interface.
+ rhs.
"""
def buildOrdinalMethodMap(interface):
@@ -1144,7 +1361,7 @@ class Interface(ReferenceKind):
return methods_by_ordinal
new_methods = buildOrdinalMethodMap(self)
- old_methods = buildOrdinalMethodMap(older_interface)
+ old_methods = buildOrdinalMethodMap(rhs)
max_old_min_version = 0
for ordinal, old_method in old_methods.items():
new_method = new_methods.get(ordinal)
@@ -1187,6 +1404,39 @@ class Interface(ReferenceKind):
return True
@property
+ def service_sandbox(self):
+ if not self.attributes:
+ return None
+ service_sandbox = self.attributes.get(ATTRIBUTE_SERVICE_SANDBOX, None)
+ if service_sandbox is None:
+ return None
+ # Constants are only allowed to refer to an enum here, so replace.
+ if isinstance(service_sandbox, Constant):
+ service_sandbox = service_sandbox.value
+ if not isinstance(service_sandbox, EnumValue):
+ raise Exception("ServiceSandbox attribute on %s must be an enum value." %
+ self.module.name)
+ return service_sandbox
+
+ @property
+ def runtime_feature(self):
+ if not self.attributes:
+ return None
+ runtime_feature = self.attributes.get(ATTRIBUTE_RUNTIME_FEATURE, None)
+ if runtime_feature is None:
+ return None
+ if not isinstance(runtime_feature, Feature):
+ raise Exception("RuntimeFeature attribute on %s must be a feature." %
+ self.name)
+ return runtime_feature
+
+ @property
+ def require_context(self):
+ if not self.attributes:
+ return None
+ return self.attributes.get(ATTRIBUTE_REQUIRE_CONTEXT, None)
+
+ @property
def stable(self):
return self.attributes.get(ATTRIBUTE_STABLE, False) \
if self.attributes else False
@@ -1199,11 +1449,18 @@ class Interface(ReferenceKind):
prefix = self.module.GetNamespacePrefix()
return '%s%s' % (prefix, self.mojom_name)
+ def _tuple(self):
+ return (self.mojom_name, self.methods, self.enums, self.constants,
+ self.attributes)
+
def __eq__(self, rhs):
- return (isinstance(rhs, Interface)
- and (self.mojom_name, self.methods, self.enums, self.constants,
- self.attributes) == (rhs.mojom_name, rhs.methods, rhs.enums,
- rhs.constants, rhs.attributes))
+ return isinstance(rhs, Interface) and self._tuple() == rhs._tuple()
+
+ def __lt__(self, rhs):
+ if not isinstance(self, type(rhs)):
+ return str(type(self)) < str(type(rhs))
+
+ return self._tuple() < rhs._tuple()
@property
def uuid(self):
@@ -1224,7 +1481,7 @@ class Interface(ReferenceKind):
class AssociatedInterface(ReferenceKind):
- ReferenceKind.AddSharedProperty('kind')
+ Kind.AddSharedProperty('kind')
def __init__(self, kind=None):
if kind is not None:
@@ -1249,7 +1506,7 @@ class AssociatedInterface(ReferenceKind):
self.kind, rhs.kind)
-class EnumField(object):
+class EnumField:
def __init__(self,
mojom_name=None,
value=None,
@@ -1281,16 +1538,25 @@ class EnumField(object):
rhs.attributes, rhs.numeric_value))
-class Enum(Kind):
+class Enum(ValueKind):
+ Kind.AddSharedProperty('mojom_name')
+ Kind.AddSharedProperty('name')
+ Kind.AddSharedProperty('native_only')
+ Kind.AddSharedProperty('fields')
+ Kind.AddSharedProperty('attributes')
+ Kind.AddSharedProperty('min_value')
+ Kind.AddSharedProperty('max_value')
+ Kind.AddSharedProperty('default_field')
+
def __init__(self, mojom_name=None, module=None, attributes=None):
- self.mojom_name = mojom_name
- self.name = None
- self.native_only = False
if mojom_name is not None:
spec = 'x:' + mojom_name
else:
spec = None
- Kind.__init__(self, spec, module)
+ ValueKind.__init__(self, spec, False, module)
+ self.mojom_name = mojom_name
+ self.name = None
+ self.native_only = False
self.fields = []
self.attributes = attributes
self.min_value = None
@@ -1300,8 +1566,7 @@ class Enum(Kind):
def Repr(self, as_ref=True):
if as_ref:
return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
- else:
- return GenericRepr(self, {'mojom_name': False, 'fields': False})
+ return GenericRepr(self, {'mojom_name': False, 'fields': False})
def Stylize(self, stylizer):
self.name = stylizer.StylizeEnum(self.mojom_name)
@@ -1327,14 +1592,14 @@ class Enum(Kind):
return '%s%s' % (prefix, self.mojom_name)
# pylint: disable=unused-argument
- def IsBackwardCompatible(self, older_enum, checker):
- """This enum is backward-compatible with older_enum if and only if one of
- the following conditions holds:
+ def IsBackwardCompatible(self, rhs, checker):
+ """This enum is backward-compatible with rhs (older_enum) if and only if one
+ of the following conditions holds:
- Neither enum is [Extensible] and both have the exact same set of valid
numeric values. Field names and aliases for the same numeric value do
not affect compatibility.
- - older_enum is [Extensible], and for every version defined by
- older_enum, this enum has the exact same set of valid numeric values.
+ - rhs is [Extensible], and for every version defined by
+ rhs, this enum has the exact same set of valid numeric values.
"""
def buildVersionFieldMap(enum):
@@ -1345,32 +1610,49 @@ class Enum(Kind):
fields_by_min_version[field.min_version].add(field.numeric_value)
return fields_by_min_version
- old_fields = buildVersionFieldMap(older_enum)
+ old_fields = buildVersionFieldMap(rhs)
new_fields = buildVersionFieldMap(self)
- if new_fields.keys() != old_fields.keys() and not older_enum.extensible:
- return False
+ if new_fields.keys() != old_fields.keys() and not rhs.extensible:
+ raise Exception("Non-extensible enum cannot be modified")
for min_version, valid_values in old_fields.items():
- if (min_version not in new_fields
- or new_fields[min_version] != valid_values):
- return False
+ if min_version not in new_fields:
+ raise Exception('New values added to an extensible enum '
+ 'do not specify MinVersion: %s' % new_fields)
+
+ if (new_fields[min_version] != valid_values):
+ if (len(new_fields[min_version]) < len(valid_values)):
+ raise Exception('Removing values for an existing MinVersion %s '
+ 'is not allowed' % min_version)
+ raise Exception(
+ 'New values don\'t match old values'
+ 'for an existing MinVersion %s,'
+ ' please specify MinVersion equal to "Next version" '
+ 'in the enum description'
+ ' for the following values:\n%s' %
+ (min_version, new_fields[min_version].difference(valid_values)))
return True
+ def _tuple(self):
+ return (self.mojom_name, self.native_only, self.fields, self.attributes,
+ self.min_value, self.max_value, self.default_field)
+
def __eq__(self, rhs):
- return (isinstance(rhs, Enum) and
- (self.mojom_name, self.native_only, self.fields, self.attributes,
- self.min_value, self.max_value,
- self.default_field) == (rhs.mojom_name, rhs.native_only,
- rhs.fields, rhs.attributes, rhs.min_value,
- rhs.max_value, rhs.default_field))
+ return isinstance(rhs, Enum) and self._tuple() == rhs._tuple()
+
+ def __lt__(self, rhs):
+ if not isinstance(self, type(rhs)):
+ return str(type(self)) < str(type(rhs))
+
+ return self._tuple() < rhs._tuple()
def __hash__(self):
return id(self)
-class Module(object):
+class Module:
def __init__(self, path=None, mojom_namespace=None, attributes=None):
self.path = path
self.mojom_namespace = mojom_namespace
@@ -1379,24 +1661,26 @@ class Module(object):
self.unions = []
self.interfaces = []
self.enums = []
+ self.features = []
self.constants = []
- self.kinds = {}
+ self.kinds = OrderedDict()
self.attributes = attributes
self.imports = []
- self.imported_kinds = {}
- self.metadata = {}
+ self.imported_kinds = OrderedDict()
+ self.metadata = OrderedDict()
def __repr__(self):
# Gives us a decent __repr__ for modules.
return self.Repr()
def __eq__(self, rhs):
- return (isinstance(rhs, Module) and
- (self.path, self.attributes, self.mojom_namespace, self.imports,
- self.constants, self.enums, self.structs, self.unions,
- self.interfaces) == (rhs.path, rhs.attributes, rhs.mojom_namespace,
- rhs.imports, rhs.constants, rhs.enums,
- rhs.structs, rhs.unions, rhs.interfaces))
+ return (isinstance(rhs, Module)
+ and (self.path, self.attributes, self.mojom_namespace, self.imports,
+ self.constants, self.enums, self.structs, self.unions,
+ self.interfaces, self.features)
+ == (rhs.path, rhs.attributes, rhs.mojom_namespace, rhs.imports,
+ rhs.constants, rhs.enums, rhs.structs, rhs.unions,
+ rhs.interfaces, rhs.features))
def __hash__(self):
return id(self)
@@ -1405,16 +1689,16 @@ class Module(object):
if as_ref:
return '<%s path=%r mojom_namespace=%r>' % (
self.__class__.__name__, self.path, self.mojom_namespace)
- else:
- return GenericRepr(
- self, {
- 'path': False,
- 'mojom_namespace': False,
- 'attributes': False,
- 'structs': False,
- 'interfaces': False,
- 'unions': False
- })
+ return GenericRepr(
+ self, {
+ 'path': False,
+ 'mojom_namespace': False,
+ 'attributes': False,
+ 'structs': False,
+ 'interfaces': False,
+ 'unions': False,
+ 'features': False,
+ })
def GetNamespacePrefix(self):
return '%s.' % self.mojom_namespace if self.mojom_namespace else ''
@@ -1434,6 +1718,11 @@ class Module(object):
self.unions.append(union)
return union
+ def AddFeature(self, mojom_name, attributes=None):
+ feature = Feature(mojom_name, self, attributes)
+ self.features.append(feature)
+ return feature
+
def Stylize(self, stylizer):
self.namespace = stylizer.StylizeModule(self.mojom_namespace)
for struct in self.structs:
@@ -1446,12 +1735,14 @@ class Module(object):
enum.Stylize(stylizer)
for constant in self.constants:
constant.Stylize(stylizer)
+ for feature in self.features:
+ feature.Stylize(stylizer)
for imported_module in self.imports:
imported_module.Stylize(stylizer)
def Dump(self, f):
- pickle.dump(self, f, 2)
+ pickle.dump(self, f)
@classmethod
def Load(cls, f):
@@ -1461,15 +1752,15 @@ class Module(object):
def IsBoolKind(kind):
- return kind.spec == BOOL.spec
+ return kind.spec == BOOL.spec or kind.spec == NULLABLE_BOOL.spec
def IsFloatKind(kind):
- return kind.spec == FLOAT.spec
+ return kind.spec == FLOAT.spec or kind.spec == NULLABLE_FLOAT.spec
def IsDoubleKind(kind):
- return kind.spec == DOUBLE.spec
+ return kind.spec == DOUBLE.spec or kind.spec == NULLABLE_DOUBLE.spec
def IsIntegralKind(kind):
@@ -1477,7 +1768,14 @@ def IsIntegralKind(kind):
or kind.spec == INT16.spec or kind.spec == INT32.spec
or kind.spec == INT64.spec or kind.spec == UINT8.spec
or kind.spec == UINT16.spec or kind.spec == UINT32.spec
- or kind.spec == UINT64.spec)
+ or kind.spec == UINT64.spec or kind.spec == NULLABLE_BOOL.spec
+ or kind.spec == NULLABLE_INT8.spec or kind.spec == NULLABLE_INT16.spec
+ or kind.spec == NULLABLE_INT32.spec
+ or kind.spec == NULLABLE_INT64.spec
+ or kind.spec == NULLABLE_UINT8.spec
+ or kind.spec == NULLABLE_UINT16.spec
+ or kind.spec == NULLABLE_UINT32.spec
+ or kind.spec == NULLABLE_UINT64.spec)
def IsStringKind(kind):
@@ -1522,6 +1820,10 @@ def IsArrayKind(kind):
return isinstance(kind, Array)
+def IsFeatureKind(kind):
+ return isinstance(kind, Feature)
+
+
def IsInterfaceKind(kind):
return isinstance(kind, Interface)
@@ -1558,12 +1860,16 @@ def IsEnumKind(kind):
return isinstance(kind, Enum)
+def IsValueKind(kind):
+ return isinstance(kind, ValueKind)
+
+
def IsReferenceKind(kind):
return isinstance(kind, ReferenceKind)
def IsNullableKind(kind):
- return IsReferenceKind(kind) and kind.is_nullable
+ return kind.is_nullable
def IsMapKind(kind):
@@ -1664,11 +1970,8 @@ def MethodPassesInterfaces(method):
return _AnyMethodParameterRecursive(method, IsInterfaceKind)
-def HasSyncMethods(interface):
- for method in interface.methods:
- if method.sync:
- return True
- return False
+def GetSyncMethodOrdinals(interface):
+ return [method.ordinal for method in interface.methods if method.sync]
def HasUninterruptableMethods(interface):
@@ -1700,18 +2003,17 @@ def ContainsHandlesOrInterfaces(kind):
checked.add(kind.spec)
if IsStructKind(kind):
return any(Check(field.kind) for field in kind.fields)
- elif IsUnionKind(kind):
+ if IsUnionKind(kind):
return any(Check(field.kind) for field in kind.fields)
- elif IsAnyHandleKind(kind):
+ if IsAnyHandleKind(kind):
return True
- elif IsAnyInterfaceKind(kind):
+ if IsAnyInterfaceKind(kind):
return True
- elif IsArrayKind(kind):
+ if IsArrayKind(kind):
return Check(kind.kind)
- elif IsMapKind(kind):
+ if IsMapKind(kind):
return Check(kind.key_kind) or Check(kind.value_kind)
- else:
- return False
+ return False
return Check(kind)
@@ -1738,21 +2040,20 @@ def ContainsNativeTypes(kind):
checked.add(kind.spec)
if IsEnumKind(kind):
return kind.native_only
- elif IsStructKind(kind):
+ if IsStructKind(kind):
if kind.native_only:
return True
if any(enum.native_only for enum in kind.enums):
return True
return any(Check(field.kind) for field in kind.fields)
- elif IsUnionKind(kind):
+ if IsUnionKind(kind):
return any(Check(field.kind) for field in kind.fields)
- elif IsInterfaceKind(kind):
+ if IsInterfaceKind(kind):
return any(enum.native_only for enum in kind.enums)
- elif IsArrayKind(kind):
+ if IsArrayKind(kind):
return Check(kind.kind)
- elif IsMapKind(kind):
+ if IsMapKind(kind):
return Check(kind.key_kind) or Check(kind.value_kind)
- else:
- return False
+ return False
return Check(kind)