| OLD | NEW |
| 1 # Copyright (C) 2013 Google Inc. All rights reserved. | 1 # Copyright (C) 2013 Google Inc. All rights reserved. |
| 2 # | 2 # |
| 3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
| 5 # met: | 5 # met: |
| 6 # | 6 # |
| 7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
| 8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
| 9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
| 10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
| 11 # in the documentation and/or other materials provided with the | 11 # in the documentation and/or other materials provided with the |
| 12 # distribution. | 12 # distribution. |
| 13 # * Neither the name of Google Inc. nor the names of its | 13 # * Neither the name of Google Inc. nor the names of its |
| 14 # contributors may be used to endorse or promote products derived from | 14 # contributors may be used to endorse or promote products derived from |
| 15 # this software without specific prior written permission. | 15 # this software without specific prior written permission. |
| 16 # | 16 # |
| 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | 28 |
| 29 """Blink IDL Intermediate Representation (IR) classes. | 29 """Blink IDL Intermediate Representation (IR) classes.""" |
| 30 | 30 |
| 31 Also JSON export, using legacy Perl terms and format, to ensure that both | |
| 32 parsers produce the same output. | |
| 33 FIXME: remove BaseIdl, JSON export (json_serializable and to_json), and Perl | |
| 34 compatibility functions and hacks once Perl compiler gone. | |
| 35 """ | |
| 36 | |
| 37 # Disable attribute hiding check (else JSONEncoder default raises an error) | |
| 38 # pylint: disable=E0202 | |
| 39 # pylint doesn't understand ABCs. | 31 # pylint doesn't understand ABCs. |
| 40 # pylint: disable=W0232, E0203, W0201 | 32 # pylint: disable=W0232, E0203, W0201 |
| 41 | 33 |
| 42 import abc | 34 import abc |
| 43 import json | |
| 44 import re | 35 import re |
| 45 | 36 |
| 46 | 37 |
| 47 # Base classes | 38 # Type classes |
| 39 |
| 40 class IdlType(object): |
| 41 # FIXME: replace type strings with these objects, |
| 42 # so don't need to parse everywhere types are used. |
| 43 # Types are stored internally as strings, not objects, |
| 44 # e.g., as 'sequence<Foo>' or 'Foo[]', |
| 45 # hence need to parse the string whenever a type is used. |
| 46 # FIXME: incorporate Nullable, Variadic, etc. |
| 47 # FIXME: properly should nest types |
| 48 # Formally types are nested, e.g., short?[] vs. short[]?, |
| 49 # but in practice these complex types aren't used and can treat |
| 50 # as orthogonal properties. |
| 51 def __init__(self, base_type, is_array=False, is_sequence=False): |
| 52 if is_array and is_sequence: |
| 53 raise ValueError('Array of Sequences are not allowed.') |
| 54 self.base_type = base_type |
| 55 self.is_array = is_array |
| 56 self.is_sequence = is_sequence |
| 57 |
| 58 def __str__(self): |
| 59 type_string = self.base_type |
| 60 if self.is_array: |
| 61 return type_string + '[]' |
| 62 if self.is_sequence: |
| 63 return 'sequence<%s>' % type_string |
| 64 return type_string |
| 65 |
| 66 @classmethod |
| 67 def from_string(cls, type_string): |
| 68 sequence_re = r'^sequence<([^>]*)>$' |
| 69 if type_string.endswith('[]'): |
| 70 type_string = type_string[:-2] |
| 71 sequence_match = re.match(sequence_re, type_string) |
| 72 if sequence_match: |
| 73 raise ValueError('Array of Sequences are not allowed.') |
| 74 return cls(type_string, is_array=True) |
| 75 sequence_match = re.match(sequence_re, type_string) |
| 76 if sequence_match: |
| 77 base_type = sequence_match.group(1) |
| 78 return cls(base_type, is_sequence=True) |
| 79 return cls(type_string) |
| 80 |
| 81 def resolve_typedefs(self, typedefs): |
| 82 if self.base_type in typedefs: |
| 83 self.base_type = typedefs[self.base_type] |
| 84 return self # Fluent interface |
| 48 | 85 |
| 49 | 86 |
| 50 class BaseIdl(object): | 87 class IdlUnionType(object): |
| 51 """Abstract base class, used for JSON serialization.""" | 88 # FIXME: remove class, just treat as tuple |
| 52 __metaclass__ = abc.ABCMeta | 89 def __init__(self, union_member_types=None): |
| 90 self.union_member_types = union_member_types or [] |
| 53 | 91 |
| 54 @abc.abstractmethod | 92 def resolve_typedefs(self, typedefs): |
| 55 def json_serializable(self): | 93 self.union_member_types = [ |
| 56 """Returns a JSON serializable form of the object. | 94 typedefs.get(union_member_type, union_member_type) |
| 57 | 95 for union_member_type in self.union_member_types] |
| 58 This should be a dictionary, with keys scoped names of the form | |
| 59 Class::key, where the scope is the class name. | |
| 60 This is so we produce identical output to the Perl code, which uses | |
| 61 the Perl module JSON.pm, which uses this format. | |
| 62 """ | |
| 63 pass | |
| 64 | 96 |
| 65 | 97 |
| 66 class TypedObject(object): | 98 class TypedObject(object): |
| 67 """Object with a type, such as an Attribute or Operation (return value). | 99 """Object with a type, such as an Attribute or Operation (return value). |
| 68 | 100 |
| 69 The type can be an actual type, or can be a typedef, which must be resolved | 101 The type can be an actual type, or can be a typedef, which must be resolved |
| 70 before passing data to the code generator. | 102 before passing data to the code generator. |
| 71 """ | 103 """ |
| 72 __metaclass__ = abc.ABCMeta | 104 __metaclass__ = abc.ABCMeta |
| 73 idl_type = None | 105 idl_type = None |
| 74 extended_attributes = None | 106 extended_attributes = None |
| 75 | 107 |
| 76 def resolve_typedefs(self, typedefs): | 108 def resolve_typedefs(self, typedefs): |
| 77 """Resolve typedefs to actual types in the object.""" | 109 """Resolve typedefs to actual types in the object.""" |
| 78 # Constructors don't have their own return type, because it's the | 110 # Constructors don't have their own return type, because it's the |
| 79 # interface itself. | 111 # interface itself. |
| 80 if not self.idl_type: | 112 if not self.idl_type: |
| 81 return | 113 return |
| 82 # (Types are represented either as strings or as IdlUnionType objects.) | 114 # (Types are represented either as strings or as IdlUnionType objects.) |
| 83 # Union types are objects, which have a member function for this | 115 # Union types are objects, which have a member function for this |
| 84 if isinstance(self.idl_type, IdlUnionType): | 116 if isinstance(self.idl_type, IdlUnionType): |
| 85 # Method 'resolve_typedefs' call is ok, but pylint can't infer this | 117 # Method 'resolve_typedefs' call is ok, but pylint can't infer this |
| 86 # pylint: disable=E1101 | 118 # pylint: disable=E1101 |
| 87 self.idl_type.resolve_typedefs(typedefs) | 119 self.idl_type.resolve_typedefs(typedefs) |
| 88 return | 120 return |
| 89 # Otherwise, IDL type is represented as string, so use a function | 121 # Otherwise, IDL type is represented as string, so use a function |
| 90 self.idl_type = resolve_typedefs(self.idl_type, typedefs) | 122 self.idl_type = resolve_typedefs(self.idl_type, typedefs) |
| 91 | 123 |
| 92 | 124 |
| 125 def resolve_typedefs(idl_type, typedefs): |
| 126 """Return an IDL type (as string) with typedefs resolved.""" |
| 127 # FIXME: merge into above, as only one use |
| 128 # Converts a string representation to and from an IdlType object to handle |
| 129 # parsing of composite types (arrays and sequences) and encapsulate typedef |
| 130 # resolution, e.g., GLint[] -> unsigned long[] requires parsing the '[]'. |
| 131 # Use fluent interface to avoid auxiliary variable. |
| 132 return str(IdlType.from_string(idl_type).resolve_typedefs(typedefs)) |
| 133 |
| 134 |
| 93 # IDL classes | 135 # IDL classes |
| 94 | 136 |
| 95 | 137 |
| 96 class IdlDefinitions(BaseIdl): | 138 class IdlDefinitions(object): |
| 97 def __init__(self, callback_functions=None, enumerations=None, file_name=Non
e, interfaces=None, typedefs=None): | 139 def __init__(self, callback_functions=None, enumerations=None, interfaces=No
ne, typedefs=None): |
| 98 self.callback_functions = callback_functions or {} | 140 self.callback_functions = callback_functions or {} |
| 99 self.enumerations = enumerations or {} | 141 self.enumerations = enumerations or {} |
| 100 self.file_name = file_name or None | |
| 101 self.interfaces = interfaces or {} | 142 self.interfaces = interfaces or {} |
| 102 # Typedefs are not exposed by bindings; resolve typedefs with the | 143 # Typedefs are not exposed by bindings; resolve typedefs with the |
| 103 # actual types and then discard the Typedefs. | 144 # actual types and then discard the Typedefs. |
| 104 # http://www.w3.org/TR/WebIDL/#idl-typedefs | 145 # http://www.w3.org/TR/WebIDL/#idl-typedefs |
| 105 if typedefs: | 146 if typedefs: |
| 106 self.resolve_typedefs(typedefs) | 147 self.resolve_typedefs(typedefs) |
| 107 | 148 |
| 108 def resolve_typedefs(self, typedefs): | 149 def resolve_typedefs(self, typedefs): |
| 109 for callback_function in self.callback_functions.itervalues(): | 150 for callback_function in self.callback_functions.itervalues(): |
| 110 callback_function.resolve_typedefs(typedefs) | 151 callback_function.resolve_typedefs(typedefs) |
| 111 for interface in self.interfaces.itervalues(): | 152 for interface in self.interfaces.itervalues(): |
| 112 interface.resolve_typedefs(typedefs) | 153 interface.resolve_typedefs(typedefs) |
| 113 | 154 |
| 114 def json_serializable(self): | |
| 115 return { | |
| 116 'idlDocument::callbackFunctions': self.callback_functions.values
(), | |
| 117 'idlDocument::enumerations': self.enumerations.values(), | |
| 118 'idlDocument::fileName': self.file_name, | |
| 119 'idlDocument::interfaces': sorted(self.interfaces.values()), | |
| 120 } | |
| 121 | 155 |
| 122 def to_json(self, debug=False): | 156 class IdlCallbackFunction(TypedObject): |
| 123 """Returns a JSON string representing the Definitions. | |
| 124 | |
| 125 The JSON output should be identical with the output of the Perl parser, | |
| 126 specifically the function serializeJSON in idl_serializer.pm, | |
| 127 which takes a Perl object created by idl_parser.pm. | |
| 128 """ | |
| 129 # Sort so order consistent, allowing comparison of output | |
| 130 if debug: | |
| 131 # indent turns on pretty-printing for legibility | |
| 132 return json.dumps(self, cls=IdlEncoder, sort_keys=True, indent=4) | |
| 133 # Use compact separators so output identical to Perl | |
| 134 return json.dumps(self, cls=IdlEncoder, sort_keys=True, separators=(',',
':')) | |
| 135 | |
| 136 | |
| 137 class IdlCallbackFunction(BaseIdl, TypedObject): | |
| 138 def __init__(self, name=None, idl_type=None, arguments=None): | 157 def __init__(self, name=None, idl_type=None, arguments=None): |
| 139 self.idl_type = idl_type | 158 self.idl_type = idl_type |
| 140 self.name = name | 159 self.name = name |
| 141 self.arguments = arguments or [] | 160 self.arguments = arguments or [] |
| 142 | 161 |
| 143 def resolve_typedefs(self, typedefs): | 162 def resolve_typedefs(self, typedefs): |
| 144 TypedObject.resolve_typedefs(self, typedefs) | 163 TypedObject.resolve_typedefs(self, typedefs) |
| 145 for argument in self.arguments: | 164 for argument in self.arguments: |
| 146 argument.resolve_typedefs(typedefs) | 165 argument.resolve_typedefs(typedefs) |
| 147 | 166 |
| 148 def json_serializable(self): | 167 |
| 149 return { | 168 class IdlEnum(object): |
| 150 'callbackFunction::name': self.name, | 169 # FIXME: remove, just treat enums as a dictionary |
| 151 'callbackFunction::type': self.idl_type, | 170 def __init__(self, name=None, values=None): |
| 152 'callbackFunction::parameters': self.arguments, | 171 self.name = name |
| 153 } | 172 self.values = values or [] # FIXME: unnecessary, can't be empty |
| 154 | 173 |
| 155 | 174 |
| 156 class IdlEnum(BaseIdl): | 175 class IdlInterface(object): |
| 157 def __init__(self, name=None, values=None): | |
| 158 self.name = name | |
| 159 self.values = values or [] | |
| 160 | |
| 161 def json_serializable(self): | |
| 162 return { | |
| 163 'domEnum::name': self.name, | |
| 164 'domEnum::values': self.values, | |
| 165 } | |
| 166 | |
| 167 | |
| 168 class IdlInterface(BaseIdl): | |
| 169 def __init__(self, attributes=None, constants=None, constructors=None, custo
m_constructors=None, extended_attributes=None, operations=None, is_callback=Fals
e, is_partial=False, name=None, parent=None): | 176 def __init__(self, attributes=None, constants=None, constructors=None, custo
m_constructors=None, extended_attributes=None, operations=None, is_callback=Fals
e, is_partial=False, name=None, parent=None): |
| 170 self.attributes = attributes or [] | 177 self.attributes = attributes or [] |
| 171 self.constants = constants or [] | 178 self.constants = constants or [] |
| 172 self.constructors = constructors or [] | 179 self.constructors = constructors or [] |
| 173 self.custom_constructors = custom_constructors or [] | 180 self.custom_constructors = custom_constructors or [] |
| 174 self.extended_attributes = extended_attributes or {} | 181 self.extended_attributes = extended_attributes or {} |
| 175 self.operations = operations or [] | 182 self.operations = operations or [] |
| 176 self.is_callback = is_callback | 183 self.is_callback = is_callback |
| 177 self.is_partial = is_partial | 184 self.is_partial = is_partial |
| 178 self.is_exception = False | 185 self.is_exception = False |
| 179 self.name = name | 186 self.name = name |
| 180 self.parent = parent | 187 self.parent = parent |
| 181 | 188 |
| 182 def resolve_typedefs(self, typedefs): | 189 def resolve_typedefs(self, typedefs): |
| 183 for attribute in self.attributes: | 190 for attribute in self.attributes: |
| 184 attribute.resolve_typedefs(typedefs) | 191 attribute.resolve_typedefs(typedefs) |
| 185 for constant in self.constants: | 192 for constant in self.constants: |
| 186 constant.resolve_typedefs(typedefs) | 193 constant.resolve_typedefs(typedefs) |
| 187 for constructor in self.constructors: | 194 for constructor in self.constructors: |
| 188 constructor.resolve_typedefs(typedefs) | 195 constructor.resolve_typedefs(typedefs) |
| 189 for custom_constructor in self.custom_constructors: | 196 for custom_constructor in self.custom_constructors: |
| 190 custom_constructor.resolve_typedefs(typedefs) | 197 custom_constructor.resolve_typedefs(typedefs) |
| 191 for operation in self.operations: | 198 for operation in self.operations: |
| 192 operation.resolve_typedefs(typedefs) | 199 operation.resolve_typedefs(typedefs) |
| 193 | 200 |
| 194 def json_serializable(self): | |
| 195 return { | |
| 196 'domInterface::attributes': self.attributes, | |
| 197 'domInterface::constants': self.constants, | |
| 198 'domInterface::constructors': self.constructors, | |
| 199 'domInterface::customConstructors': self.custom_constructors, | |
| 200 'domInterface::extendedAttributes': none_to_value_is_missing(self.ex
tended_attributes), | |
| 201 'domInterface::functions': self.operations, | |
| 202 'domInterface::isException': false_to_none(self.is_exception), | |
| 203 'domInterface::isCallback': boolean_to_perl(false_to_none(self.is_ca
llback)), | |
| 204 'domInterface::isPartial': false_to_none(self.is_partial), | |
| 205 'domInterface::name': self.name, | |
| 206 'domInterface::parent': self.parent, | |
| 207 } | |
| 208 | |
| 209 | 201 |
| 210 class IdlException(IdlInterface): | 202 class IdlException(IdlInterface): |
| 211 # Properly exceptions and interfaces are distinct, and thus should inherit a | 203 # Properly exceptions and interfaces are distinct, and thus should inherit a |
| 212 # common base class (say, "IdlExceptionOrInterface"). | 204 # common base class (say, "IdlExceptionOrInterface"). |
| 213 # However, there is only one exception (DOMException), and new exceptions | 205 # However, there is only one exception (DOMException), and new exceptions |
| 214 # are not expected. Thus it is easier to implement exceptions as a | 206 # are not expected. Thus it is easier to implement exceptions as a |
| 215 # restricted subclass of interfaces. | 207 # restricted subclass of interfaces. |
| 216 # http://www.w3.org/TR/WebIDL/#idl-exceptions | 208 # http://www.w3.org/TR/WebIDL/#idl-exceptions |
| 217 def __init__(self, name=None, constants=None, operations=None, attributes=No
ne, extended_attributes=None): | 209 def __init__(self, name=None, constants=None, operations=None, attributes=No
ne, extended_attributes=None): |
| 218 IdlInterface.__init__(self, name=name, constants=constants, operations=o
perations, attributes=attributes, extended_attributes=extended_attributes) | 210 IdlInterface.__init__(self, name=name, constants=constants, operations=o
perations, attributes=attributes, extended_attributes=extended_attributes) |
| 219 self.is_exception = True | 211 self.is_exception = True |
| 220 | 212 |
| 221 | 213 |
| 222 class IdlAttribute(BaseIdl, TypedObject): | 214 class IdlAttribute(TypedObject): |
| 223 def __init__(self, idl_type=None, extended_attributes=None, getter_exception
s=None, is_nullable=False, is_static=False, is_read_only=False, name=None, sette
r_exceptions=None): | 215 def __init__(self, idl_type=None, extended_attributes=None, getter_exception
s=None, is_nullable=False, is_static=False, is_read_only=False, name=None, sette
r_exceptions=None): |
| 224 self.idl_type = idl_type | 216 self.idl_type = idl_type |
| 225 self.extended_attributes = extended_attributes or {} | 217 self.extended_attributes = extended_attributes or {} |
| 226 self.getter_exceptions = getter_exceptions or [] | 218 self.getter_exceptions = getter_exceptions or [] |
| 227 self.is_nullable = is_nullable | 219 self.is_nullable = is_nullable |
| 228 self.is_static = is_static | 220 self.is_static = is_static |
| 229 self.is_read_only = is_read_only | 221 self.is_read_only = is_read_only |
| 230 self.name = name | 222 self.name = name |
| 231 self.setter_exceptions = setter_exceptions or [] | 223 self.setter_exceptions = setter_exceptions or [] |
| 232 | 224 |
| 233 def json_serializable(self): | |
| 234 return { | |
| 235 'domAttribute::extendedAttributes': none_to_value_is_missing(self.ex
tended_attributes), | |
| 236 'domAttribute::getterExceptions': self.getter_exceptions, | |
| 237 'domAttribute::isNullable': boolean_to_perl_quoted(false_to_none(sel
f.is_nullable)), | |
| 238 'domAttribute::isReadOnly': boolean_to_perl(false_to_none(self.is_re
ad_only)), | |
| 239 'domAttribute::isStatic': boolean_to_perl(false_to_none(self.is_stat
ic)), | |
| 240 'domAttribute::name': self.name, | |
| 241 'domAttribute::setterExceptions': self.setter_exceptions, | |
| 242 'domAttribute::type': self.idl_type, | |
| 243 } | |
| 244 | 225 |
| 245 | 226 class IdlConstant(TypedObject): |
| 246 class IdlConstant(BaseIdl, TypedObject): | |
| 247 def __init__(self, name=None, idl_type=None, value=None, extended_attributes
=None): | 227 def __init__(self, name=None, idl_type=None, value=None, extended_attributes
=None): |
| 248 self.idl_type = idl_type | 228 self.idl_type = idl_type |
| 249 self.extended_attributes = extended_attributes or {} | 229 self.extended_attributes = extended_attributes or {} |
| 250 self.name = name | 230 self.name = name |
| 251 self.value = value | 231 self.value = value |
| 252 | 232 |
| 253 def json_serializable(self): | |
| 254 return { | |
| 255 'domConstant::extendedAttributes': none_to_value_is_missing(self.ext
ended_attributes), | |
| 256 'domConstant::name': self.name, | |
| 257 'domConstant::type': self.idl_type, | |
| 258 'domConstant::value': self.value, | |
| 259 } | |
| 260 | 233 |
| 261 | 234 class IdlOperation(TypedObject): |
| 262 class IdlOperation(BaseIdl, TypedObject): | |
| 263 def __init__(self, is_static=False, name=None, idl_type=None, extended_attri
butes=None, specials=None, arguments=None, overloaded_index=None): | 235 def __init__(self, is_static=False, name=None, idl_type=None, extended_attri
butes=None, specials=None, arguments=None, overloaded_index=None): |
| 264 self.is_static = is_static | 236 self.is_static = is_static |
| 265 self.name = name or '' | 237 self.name = name or '' |
| 266 self.idl_type = idl_type | 238 self.idl_type = idl_type |
| 267 self.extended_attributes = extended_attributes or {} | 239 self.extended_attributes = extended_attributes or {} |
| 268 self.specials = specials or [] | 240 self.specials = specials or [] |
| 269 self.arguments = arguments or [] | 241 self.arguments = arguments or [] |
| 270 # FIXME: remove overloaded_index (only here for Perl compatibility), | |
| 271 # as overloading is handled in code generator (v8_interface.py). | |
| 272 self.overloaded_index = overloaded_index | |
| 273 | 242 |
| 274 def resolve_typedefs(self, typedefs): | 243 def resolve_typedefs(self, typedefs): |
| 275 TypedObject.resolve_typedefs(self, typedefs) | 244 TypedObject.resolve_typedefs(self, typedefs) |
| 276 for argument in self.arguments: | 245 for argument in self.arguments: |
| 277 argument.resolve_typedefs(typedefs) | 246 argument.resolve_typedefs(typedefs) |
| 278 | 247 |
| 279 def json_serializable(self): | |
| 280 return { | |
| 281 'domFunction::extendedAttributes': none_to_value_is_missing(self.ext
ended_attributes), | |
| 282 'domFunction::isStatic': boolean_to_perl(false_to_none(self.is_stati
c)), | |
| 283 'domFunction::name': self.name, | |
| 284 'domFunction::overloadedIndex': self.overloaded_index, | |
| 285 'domFunction::parameters': self.arguments, | |
| 286 'domFunction::specials': self.specials, | |
| 287 'domFunction::type': self.idl_type, | |
| 288 } | |
| 289 | 248 |
| 290 | 249 class IdlArgument(TypedObject): |
| 291 class IdlArgument(BaseIdl, TypedObject): | 250 def __init__(self, name=None, idl_type=None, extended_attributes=None, is_op
tional=False, is_nullable=False, is_variadic=False): |
| 292 def __init__(self, name=None, idl_type=None, extended_attributes=None, is_op
tional=False, is_nullable=None, is_variadic=False): | |
| 293 self.idl_type = idl_type | 251 self.idl_type = idl_type |
| 294 self.extended_attributes = extended_attributes or {} | 252 self.extended_attributes = extended_attributes or {} |
| 295 # FIXME: boolean values are inconsistent. | |
| 296 # The below hack is so that generated JSON is identical to | |
| 297 # Perl-generated JSON, where the exact values depend on the code path. | |
| 298 # False and None (Perl: 0 and undef) are semantically interchangeable, | |
| 299 # but yield different JSON. | |
| 300 # Once Perl removed, have all default to False. | |
| 301 if is_optional is None: | |
| 302 is_optional = False | |
| 303 if is_variadic is None: | |
| 304 is_variadic = False | |
| 305 self.is_nullable = is_nullable # (T?) | 253 self.is_nullable = is_nullable # (T?) |
| 306 self.is_optional = is_optional # (optional T) | 254 self.is_optional = is_optional # (optional T) |
| 307 self.is_variadic = is_variadic # (T...) | 255 self.is_variadic = is_variadic # (T...) |
| 308 self.name = name | 256 self.name = name |
| 309 | |
| 310 def json_serializable(self): | |
| 311 return { | |
| 312 'domParameter::extendedAttributes': none_to_value_is_missing(self.ex
tended_attributes), | |
| 313 'domParameter::isNullable': boolean_to_perl_quoted(self.is_nullable)
, | |
| 314 'domParameter::isOptional': boolean_to_perl(self.is_optional), | |
| 315 'domParameter::isVariadic': boolean_to_perl(self.is_variadic), | |
| 316 'domParameter::name': self.name, | |
| 317 'domParameter::type': self.idl_type, | |
| 318 } | |
| 319 | |
| 320 # Type classes | |
| 321 | |
| 322 | |
| 323 def resolve_typedefs(idl_type, typedefs): | |
| 324 """Return an IDL type (as string) with typedefs resolved.""" | |
| 325 # Converts a string representation to and from an IdlType object to handle | |
| 326 # parsing of composite types (arrays and sequences) and encapsulate typedef | |
| 327 # resolution, e.g., GLint[] -> unsigned long[] requires parsing the '[]'. | |
| 328 # Use fluent interface to avoid auxiliary variable. | |
| 329 return str(IdlType.from_string(idl_type).resolve_typedefs(typedefs)) | |
| 330 | |
| 331 | |
| 332 class IdlType(object): | |
| 333 # FIXME: replace type strings with these objects, | |
| 334 # so don't need to parse everywhere types are used. | |
| 335 # Types are stored internally as strings, not objects, | |
| 336 # e.g., as 'sequence<Foo>' or 'Foo[]', | |
| 337 # hence need to parse the string whenever a type is used. | |
| 338 # FIXME: incorporate Nullable, Variadic, etc. | |
| 339 # FIXME: properly should nest types | |
| 340 # Formally types are nested, e.g., short?[] vs. short[]?, | |
| 341 # but in practice these complex types aren't used and can treat | |
| 342 # as orthogonal properties. | |
| 343 def __init__(self, base_type, is_array=False, is_sequence=False): | |
| 344 if is_array and is_sequence: | |
| 345 raise ValueError('Array of Sequences are not allowed.') | |
| 346 self.base_type = base_type | |
| 347 self.is_array = is_array | |
| 348 self.is_sequence = is_sequence | |
| 349 | |
| 350 def __str__(self): | |
| 351 type_string = self.base_type | |
| 352 if self.is_array: | |
| 353 return type_string + '[]' | |
| 354 if self.is_sequence: | |
| 355 return 'sequence<%s>' % type_string | |
| 356 return type_string | |
| 357 | |
| 358 @classmethod | |
| 359 def from_string(cls, type_string): | |
| 360 sequence_re = r'^sequence<([^>]*)>$' | |
| 361 if type_string.endswith('[]'): | |
| 362 type_string = type_string[:-2] | |
| 363 sequence_match = re.match(sequence_re, type_string) | |
| 364 if sequence_match: | |
| 365 raise ValueError('Array of Sequences are not allowed.') | |
| 366 return cls(type_string, is_array=True) | |
| 367 sequence_match = re.match(sequence_re, type_string) | |
| 368 if sequence_match: | |
| 369 base_type = sequence_match.group(1) | |
| 370 return cls(base_type, is_sequence=True) | |
| 371 return cls(type_string) | |
| 372 | |
| 373 def resolve_typedefs(self, typedefs): | |
| 374 if self.base_type in typedefs: | |
| 375 self.base_type = typedefs[self.base_type] | |
| 376 return self # Fluent interface | |
| 377 | |
| 378 | |
| 379 class IdlUnionType(BaseIdl): | |
| 380 def __init__(self, union_member_types=None): | |
| 381 self.union_member_types = union_member_types or [] | |
| 382 | |
| 383 def resolve_typedefs(self, typedefs): | |
| 384 self.union_member_types = [ | |
| 385 typedefs.get(union_member_type, union_member_type) | |
| 386 for union_member_type in self.union_member_types] | |
| 387 | |
| 388 def json_serializable(self): | |
| 389 return { | |
| 390 'UnionType::unionMemberTypes': self.union_member_types, | |
| 391 } | |
| 392 | |
| 393 | |
| 394 # Perl JSON compatibility functions | |
| 395 | |
| 396 def none_to_value_is_missing(extended_attributes): | |
| 397 # Perl IDL Parser uses 'VALUE_IS_MISSING' for null values in | |
| 398 # extended attributes, so add this as a filter when exporting to JSON. | |
| 399 new_extended_attributes = {} | |
| 400 for key, value in extended_attributes.iteritems(): | |
| 401 if value is None: | |
| 402 new_extended_attributes[key] = 'VALUE_IS_MISSING' | |
| 403 else: | |
| 404 new_extended_attributes[key] = value | |
| 405 return new_extended_attributes | |
| 406 | |
| 407 | |
| 408 def boolean_to_perl(value): | |
| 409 # Perl stores booleans as 1, 0, or undefined (JSON null); | |
| 410 # convert to this format. | |
| 411 if value is None: | |
| 412 return None | |
| 413 return int(value) | |
| 414 | |
| 415 | |
| 416 def boolean_to_perl_quoted(value): | |
| 417 # Bug-for-bug compatibility with Perl. | |
| 418 # The value of isNullable is quoted ('1', '0', or undefined), rather than | |
| 419 # an integer, so add quotes. | |
| 420 if value is None: | |
| 421 return None | |
| 422 return str(int(value)) | |
| 423 | |
| 424 | |
| 425 def false_to_none(value): | |
| 426 # The Perl parser generally uses undefined (Python None) rather than False | |
| 427 # for boolean flags, because the value is simply left undefined, rather than | |
| 428 # explicitly set to False. | |
| 429 if value is False: | |
| 430 return None | |
| 431 return value | |
| 432 | |
| 433 | |
| 434 # JSON export | |
| 435 | |
| 436 | |
| 437 class IdlEncoder(json.JSONEncoder): | |
| 438 def default(self, obj): | |
| 439 if isinstance(obj, BaseIdl): | |
| 440 return obj.json_serializable() | |
| 441 return json.JSONEncoder.default(self, obj) | |
| OLD | NEW |