Index: Source/bindings/scripts/idl_definitions.py |
diff --git a/Source/bindings/scripts/idl_definitions.py b/Source/bindings/scripts/idl_definitions.py |
index 623ca48316dd54ebff82cbda9d694bd17fe51cd8..b0fe3a34f028500fdfacabd0ed694f3ca73b41d8 100644 |
--- a/Source/bindings/scripts/idl_definitions.py |
+++ b/Source/bindings/scripts/idl_definitions.py |
@@ -26,41 +26,73 @@ |
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
-"""Blink IDL Intermediate Representation (IR) classes. |
+"""Blink IDL Intermediate Representation (IR) classes.""" |
-Also JSON export, using legacy Perl terms and format, to ensure that both |
-parsers produce the same output. |
-FIXME: remove BaseIdl, JSON export (json_serializable and to_json), and Perl |
-compatibility functions and hacks once Perl compiler gone. |
-""" |
- |
-# Disable attribute hiding check (else JSONEncoder default raises an error) |
-# pylint: disable=E0202 |
# pylint doesn't understand ABCs. |
# pylint: disable=W0232, E0203, W0201 |
import abc |
-import json |
import re |
-# Base classes |
+# Type classes |
+ |
+class IdlType(object): |
+ # FIXME: replace type strings with these objects, |
+ # so don't need to parse everywhere types are used. |
+ # Types are stored internally as strings, not objects, |
+ # e.g., as 'sequence<Foo>' or 'Foo[]', |
+ # hence need to parse the string whenever a type is used. |
+ # FIXME: incorporate Nullable, Variadic, etc. |
+ # FIXME: properly should nest types |
+ # Formally types are nested, e.g., short?[] vs. short[]?, |
+ # but in practice these complex types aren't used and can treat |
+ # as orthogonal properties. |
+ def __init__(self, base_type, is_array=False, is_sequence=False): |
+ if is_array and is_sequence: |
+ raise ValueError('Array of Sequences are not allowed.') |
+ self.base_type = base_type |
+ self.is_array = is_array |
+ self.is_sequence = is_sequence |
+ def __str__(self): |
+ type_string = self.base_type |
+ if self.is_array: |
+ return type_string + '[]' |
+ if self.is_sequence: |
+ return 'sequence<%s>' % type_string |
+ return type_string |
-class BaseIdl(object): |
- """Abstract base class, used for JSON serialization.""" |
- __metaclass__ = abc.ABCMeta |
+ @classmethod |
+ def from_string(cls, type_string): |
+ sequence_re = r'^sequence<([^>]*)>$' |
+ if type_string.endswith('[]'): |
+ type_string = type_string[:-2] |
+ sequence_match = re.match(sequence_re, type_string) |
+ if sequence_match: |
+ raise ValueError('Array of Sequences are not allowed.') |
+ return cls(type_string, is_array=True) |
+ sequence_match = re.match(sequence_re, type_string) |
+ if sequence_match: |
+ base_type = sequence_match.group(1) |
+ return cls(base_type, is_sequence=True) |
+ return cls(type_string) |
- @abc.abstractmethod |
- def json_serializable(self): |
- """Returns a JSON serializable form of the object. |
+ def resolve_typedefs(self, typedefs): |
+ if self.base_type in typedefs: |
+ self.base_type = typedefs[self.base_type] |
+ return self # Fluent interface |
- This should be a dictionary, with keys scoped names of the form |
- Class::key, where the scope is the class name. |
- This is so we produce identical output to the Perl code, which uses |
- the Perl module JSON.pm, which uses this format. |
- """ |
- pass |
+ |
+class IdlUnionType(object): |
+ # FIXME: remove class, just treat as tuple |
+ def __init__(self, union_member_types=None): |
+ self.union_member_types = union_member_types or [] |
+ |
+ def resolve_typedefs(self, typedefs): |
+ self.union_member_types = [ |
+ typedefs.get(union_member_type, union_member_type) |
+ for union_member_type in self.union_member_types] |
class TypedObject(object): |
@@ -90,14 +122,23 @@ class TypedObject(object): |
self.idl_type = resolve_typedefs(self.idl_type, typedefs) |
+def resolve_typedefs(idl_type, typedefs): |
+ """Return an IDL type (as string) with typedefs resolved.""" |
+ # FIXME: merge into above, as only one use |
+ # Converts a string representation to and from an IdlType object to handle |
+ # parsing of composite types (arrays and sequences) and encapsulate typedef |
+ # resolution, e.g., GLint[] -> unsigned long[] requires parsing the '[]'. |
+ # Use fluent interface to avoid auxiliary variable. |
+ return str(IdlType.from_string(idl_type).resolve_typedefs(typedefs)) |
+ |
+ |
# IDL classes |
-class IdlDefinitions(BaseIdl): |
- def __init__(self, callback_functions=None, enumerations=None, file_name=None, interfaces=None, typedefs=None): |
+class IdlDefinitions(object): |
+ def __init__(self, callback_functions=None, enumerations=None, interfaces=None, typedefs=None): |
self.callback_functions = callback_functions or {} |
self.enumerations = enumerations or {} |
- self.file_name = file_name or None |
self.interfaces = interfaces or {} |
# Typedefs are not exposed by bindings; resolve typedefs with the |
# actual types and then discard the Typedefs. |
@@ -111,30 +152,8 @@ class IdlDefinitions(BaseIdl): |
for interface in self.interfaces.itervalues(): |
interface.resolve_typedefs(typedefs) |
- def json_serializable(self): |
- return { |
- 'idlDocument::callbackFunctions': self.callback_functions.values(), |
- 'idlDocument::enumerations': self.enumerations.values(), |
- 'idlDocument::fileName': self.file_name, |
- 'idlDocument::interfaces': sorted(self.interfaces.values()), |
- } |
- |
- def to_json(self, debug=False): |
- """Returns a JSON string representing the Definitions. |
- |
- The JSON output should be identical with the output of the Perl parser, |
- specifically the function serializeJSON in idl_serializer.pm, |
- which takes a Perl object created by idl_parser.pm. |
- """ |
- # Sort so order consistent, allowing comparison of output |
- if debug: |
- # indent turns on pretty-printing for legibility |
- return json.dumps(self, cls=IdlEncoder, sort_keys=True, indent=4) |
- # Use compact separators so output identical to Perl |
- return json.dumps(self, cls=IdlEncoder, sort_keys=True, separators=(',', ':')) |
- |
- |
-class IdlCallbackFunction(BaseIdl, TypedObject): |
+ |
+class IdlCallbackFunction(TypedObject): |
def __init__(self, name=None, idl_type=None, arguments=None): |
self.idl_type = idl_type |
self.name = name |
@@ -145,27 +164,15 @@ class IdlCallbackFunction(BaseIdl, TypedObject): |
for argument in self.arguments: |
argument.resolve_typedefs(typedefs) |
- def json_serializable(self): |
- return { |
- 'callbackFunction::name': self.name, |
- 'callbackFunction::type': self.idl_type, |
- 'callbackFunction::parameters': self.arguments, |
- } |
- |
-class IdlEnum(BaseIdl): |
+class IdlEnum(object): |
+ # FIXME: remove, just treat enums as a dictionary |
def __init__(self, name=None, values=None): |
self.name = name |
- self.values = values or [] |
+ self.values = values or [] # FIXME: unnecessary, can't be empty |
- def json_serializable(self): |
- return { |
- 'domEnum::name': self.name, |
- 'domEnum::values': self.values, |
- } |
- |
-class IdlInterface(BaseIdl): |
+class IdlInterface(object): |
def __init__(self, attributes=None, constants=None, constructors=None, custom_constructors=None, extended_attributes=None, operations=None, is_callback=False, is_partial=False, name=None, parent=None): |
self.attributes = attributes or [] |
self.constants = constants or [] |
@@ -191,21 +198,6 @@ class IdlInterface(BaseIdl): |
for operation in self.operations: |
operation.resolve_typedefs(typedefs) |
- def json_serializable(self): |
- return { |
- 'domInterface::attributes': self.attributes, |
- 'domInterface::constants': self.constants, |
- 'domInterface::constructors': self.constructors, |
- 'domInterface::customConstructors': self.custom_constructors, |
- 'domInterface::extendedAttributes': none_to_value_is_missing(self.extended_attributes), |
- 'domInterface::functions': self.operations, |
- 'domInterface::isException': false_to_none(self.is_exception), |
- 'domInterface::isCallback': boolean_to_perl(false_to_none(self.is_callback)), |
- 'domInterface::isPartial': false_to_none(self.is_partial), |
- 'domInterface::name': self.name, |
- 'domInterface::parent': self.parent, |
- } |
- |
class IdlException(IdlInterface): |
# Properly exceptions and interfaces are distinct, and thus should inherit a |
@@ -219,7 +211,7 @@ class IdlException(IdlInterface): |
self.is_exception = True |
-class IdlAttribute(BaseIdl, TypedObject): |
+class IdlAttribute(TypedObject): |
def __init__(self, idl_type=None, extended_attributes=None, getter_exceptions=None, is_nullable=False, is_static=False, is_read_only=False, name=None, setter_exceptions=None): |
self.idl_type = idl_type |
self.extended_attributes = extended_attributes or {} |
@@ -230,36 +222,16 @@ class IdlAttribute(BaseIdl, TypedObject): |
self.name = name |
self.setter_exceptions = setter_exceptions or [] |
- def json_serializable(self): |
- return { |
- 'domAttribute::extendedAttributes': none_to_value_is_missing(self.extended_attributes), |
- 'domAttribute::getterExceptions': self.getter_exceptions, |
- 'domAttribute::isNullable': boolean_to_perl_quoted(false_to_none(self.is_nullable)), |
- 'domAttribute::isReadOnly': boolean_to_perl(false_to_none(self.is_read_only)), |
- 'domAttribute::isStatic': boolean_to_perl(false_to_none(self.is_static)), |
- 'domAttribute::name': self.name, |
- 'domAttribute::setterExceptions': self.setter_exceptions, |
- 'domAttribute::type': self.idl_type, |
- } |
- |
-class IdlConstant(BaseIdl, TypedObject): |
+class IdlConstant(TypedObject): |
def __init__(self, name=None, idl_type=None, value=None, extended_attributes=None): |
self.idl_type = idl_type |
self.extended_attributes = extended_attributes or {} |
self.name = name |
self.value = value |
- def json_serializable(self): |
- return { |
- 'domConstant::extendedAttributes': none_to_value_is_missing(self.extended_attributes), |
- 'domConstant::name': self.name, |
- 'domConstant::type': self.idl_type, |
- 'domConstant::value': self.value, |
- } |
- |
-class IdlOperation(BaseIdl, TypedObject): |
+class IdlOperation(TypedObject): |
def __init__(self, is_static=False, name=None, idl_type=None, extended_attributes=None, specials=None, arguments=None, overloaded_index=None): |
self.is_static = is_static |
self.name = name or '' |
@@ -267,175 +239,18 @@ class IdlOperation(BaseIdl, TypedObject): |
self.extended_attributes = extended_attributes or {} |
self.specials = specials or [] |
self.arguments = arguments or [] |
- # FIXME: remove overloaded_index (only here for Perl compatibility), |
- # as overloading is handled in code generator (v8_interface.py). |
- self.overloaded_index = overloaded_index |
def resolve_typedefs(self, typedefs): |
TypedObject.resolve_typedefs(self, typedefs) |
for argument in self.arguments: |
argument.resolve_typedefs(typedefs) |
- def json_serializable(self): |
- return { |
- 'domFunction::extendedAttributes': none_to_value_is_missing(self.extended_attributes), |
- 'domFunction::isStatic': boolean_to_perl(false_to_none(self.is_static)), |
- 'domFunction::name': self.name, |
- 'domFunction::overloadedIndex': self.overloaded_index, |
- 'domFunction::parameters': self.arguments, |
- 'domFunction::specials': self.specials, |
- 'domFunction::type': self.idl_type, |
- } |
- |
-class IdlArgument(BaseIdl, TypedObject): |
- def __init__(self, name=None, idl_type=None, extended_attributes=None, is_optional=False, is_nullable=None, is_variadic=False): |
+class IdlArgument(TypedObject): |
+ def __init__(self, name=None, idl_type=None, extended_attributes=None, is_optional=False, is_nullable=False, is_variadic=False): |
self.idl_type = idl_type |
self.extended_attributes = extended_attributes or {} |
- # FIXME: boolean values are inconsistent. |
- # The below hack is so that generated JSON is identical to |
- # Perl-generated JSON, where the exact values depend on the code path. |
- # False and None (Perl: 0 and undef) are semantically interchangeable, |
- # but yield different JSON. |
- # Once Perl removed, have all default to False. |
- if is_optional is None: |
- is_optional = False |
- if is_variadic is None: |
- is_variadic = False |
self.is_nullable = is_nullable # (T?) |
self.is_optional = is_optional # (optional T) |
self.is_variadic = is_variadic # (T...) |
self.name = name |
- |
- def json_serializable(self): |
- return { |
- 'domParameter::extendedAttributes': none_to_value_is_missing(self.extended_attributes), |
- 'domParameter::isNullable': boolean_to_perl_quoted(self.is_nullable), |
- 'domParameter::isOptional': boolean_to_perl(self.is_optional), |
- 'domParameter::isVariadic': boolean_to_perl(self.is_variadic), |
- 'domParameter::name': self.name, |
- 'domParameter::type': self.idl_type, |
- } |
- |
-# Type classes |
- |
- |
-def resolve_typedefs(idl_type, typedefs): |
- """Return an IDL type (as string) with typedefs resolved.""" |
- # Converts a string representation to and from an IdlType object to handle |
- # parsing of composite types (arrays and sequences) and encapsulate typedef |
- # resolution, e.g., GLint[] -> unsigned long[] requires parsing the '[]'. |
- # Use fluent interface to avoid auxiliary variable. |
- return str(IdlType.from_string(idl_type).resolve_typedefs(typedefs)) |
- |
- |
-class IdlType(object): |
- # FIXME: replace type strings with these objects, |
- # so don't need to parse everywhere types are used. |
- # Types are stored internally as strings, not objects, |
- # e.g., as 'sequence<Foo>' or 'Foo[]', |
- # hence need to parse the string whenever a type is used. |
- # FIXME: incorporate Nullable, Variadic, etc. |
- # FIXME: properly should nest types |
- # Formally types are nested, e.g., short?[] vs. short[]?, |
- # but in practice these complex types aren't used and can treat |
- # as orthogonal properties. |
- def __init__(self, base_type, is_array=False, is_sequence=False): |
- if is_array and is_sequence: |
- raise ValueError('Array of Sequences are not allowed.') |
- self.base_type = base_type |
- self.is_array = is_array |
- self.is_sequence = is_sequence |
- |
- def __str__(self): |
- type_string = self.base_type |
- if self.is_array: |
- return type_string + '[]' |
- if self.is_sequence: |
- return 'sequence<%s>' % type_string |
- return type_string |
- |
- @classmethod |
- def from_string(cls, type_string): |
- sequence_re = r'^sequence<([^>]*)>$' |
- if type_string.endswith('[]'): |
- type_string = type_string[:-2] |
- sequence_match = re.match(sequence_re, type_string) |
- if sequence_match: |
- raise ValueError('Array of Sequences are not allowed.') |
- return cls(type_string, is_array=True) |
- sequence_match = re.match(sequence_re, type_string) |
- if sequence_match: |
- base_type = sequence_match.group(1) |
- return cls(base_type, is_sequence=True) |
- return cls(type_string) |
- |
- def resolve_typedefs(self, typedefs): |
- if self.base_type in typedefs: |
- self.base_type = typedefs[self.base_type] |
- return self # Fluent interface |
- |
- |
-class IdlUnionType(BaseIdl): |
- def __init__(self, union_member_types=None): |
- self.union_member_types = union_member_types or [] |
- |
- def resolve_typedefs(self, typedefs): |
- self.union_member_types = [ |
- typedefs.get(union_member_type, union_member_type) |
- for union_member_type in self.union_member_types] |
- |
- def json_serializable(self): |
- return { |
- 'UnionType::unionMemberTypes': self.union_member_types, |
- } |
- |
- |
-# Perl JSON compatibility functions |
- |
-def none_to_value_is_missing(extended_attributes): |
- # Perl IDL Parser uses 'VALUE_IS_MISSING' for null values in |
- # extended attributes, so add this as a filter when exporting to JSON. |
- new_extended_attributes = {} |
- for key, value in extended_attributes.iteritems(): |
- if value is None: |
- new_extended_attributes[key] = 'VALUE_IS_MISSING' |
- else: |
- new_extended_attributes[key] = value |
- return new_extended_attributes |
- |
- |
-def boolean_to_perl(value): |
- # Perl stores booleans as 1, 0, or undefined (JSON null); |
- # convert to this format. |
- if value is None: |
- return None |
- return int(value) |
- |
- |
-def boolean_to_perl_quoted(value): |
- # Bug-for-bug compatibility with Perl. |
- # The value of isNullable is quoted ('1', '0', or undefined), rather than |
- # an integer, so add quotes. |
- if value is None: |
- return None |
- return str(int(value)) |
- |
- |
-def false_to_none(value): |
- # The Perl parser generally uses undefined (Python None) rather than False |
- # for boolean flags, because the value is simply left undefined, rather than |
- # explicitly set to False. |
- if value is False: |
- return None |
- return value |
- |
- |
-# JSON export |
- |
- |
-class IdlEncoder(json.JSONEncoder): |
- def default(self, obj): |
- if isinstance(obj, BaseIdl): |
- return obj.json_serializable() |
- return json.JSONEncoder.default(self, obj) |