Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | # This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 4 | |
michael@0 | 5 | """ A WebIDL parser. """ |
michael@0 | 6 | |
michael@0 | 7 | from ply import lex, yacc |
michael@0 | 8 | import re |
michael@0 | 9 | import os |
michael@0 | 10 | import traceback |
michael@0 | 11 | import math |
michael@0 | 12 | |
michael@0 | 13 | # Machinery |
michael@0 | 14 | |
michael@0 | 15 | def parseInt(literal): |
michael@0 | 16 | string = literal |
michael@0 | 17 | sign = 0 |
michael@0 | 18 | base = 0 |
michael@0 | 19 | |
michael@0 | 20 | if string[0] == '-': |
michael@0 | 21 | sign = -1 |
michael@0 | 22 | string = string[1:] |
michael@0 | 23 | else: |
michael@0 | 24 | sign = 1 |
michael@0 | 25 | |
michael@0 | 26 | if string[0] == '0' and len(string) > 1: |
michael@0 | 27 | if string[1] == 'x' or string[1] == 'X': |
michael@0 | 28 | base = 16 |
michael@0 | 29 | string = string[2:] |
michael@0 | 30 | else: |
michael@0 | 31 | base = 8 |
michael@0 | 32 | string = string[1:] |
michael@0 | 33 | else: |
michael@0 | 34 | base = 10 |
michael@0 | 35 | |
michael@0 | 36 | value = int(string, base) |
michael@0 | 37 | return value * sign |
michael@0 | 38 | |
michael@0 | 39 | # Magic for creating enums |
michael@0 | 40 | def M_add_class_attribs(attribs, start): |
michael@0 | 41 | def foo(name, bases, dict_): |
michael@0 | 42 | for v, k in enumerate(attribs): |
michael@0 | 43 | dict_[k] = start + v |
michael@0 | 44 | assert 'length' not in dict_ |
michael@0 | 45 | dict_['length'] = start + len(attribs) |
michael@0 | 46 | return type(name, bases, dict_) |
michael@0 | 47 | return foo |
michael@0 | 48 | |
michael@0 | 49 | def enum(*names, **kw): |
michael@0 | 50 | if len(kw) == 1: |
michael@0 | 51 | base = kw['base'].__class__ |
michael@0 | 52 | start = base.length |
michael@0 | 53 | else: |
michael@0 | 54 | assert len(kw) == 0 |
michael@0 | 55 | base = object |
michael@0 | 56 | start = 0 |
michael@0 | 57 | class Foo(base): |
michael@0 | 58 | __metaclass__ = M_add_class_attribs(names, start) |
michael@0 | 59 | def __setattr__(self, name, value): # this makes it read-only |
michael@0 | 60 | raise NotImplementedError |
michael@0 | 61 | return Foo() |
michael@0 | 62 | |
michael@0 | 63 | class WebIDLError(Exception): |
michael@0 | 64 | def __init__(self, message, locations, warning=False): |
michael@0 | 65 | self.message = message |
michael@0 | 66 | self.locations = [str(loc) for loc in locations] |
michael@0 | 67 | self.warning = warning |
michael@0 | 68 | |
michael@0 | 69 | def __str__(self): |
michael@0 | 70 | return "%s: %s%s%s" % (self.warning and 'warning' or 'error', |
michael@0 | 71 | self.message, |
michael@0 | 72 | ", " if len(self.locations) != 0 else "", |
michael@0 | 73 | "\n".join(self.locations)) |
michael@0 | 74 | |
michael@0 | 75 | class Location(object): |
michael@0 | 76 | def __init__(self, lexer, lineno, lexpos, filename): |
michael@0 | 77 | self._line = None |
michael@0 | 78 | self._lineno = lineno |
michael@0 | 79 | self._lexpos = lexpos |
michael@0 | 80 | self._lexdata = lexer.lexdata |
michael@0 | 81 | self._file = filename if filename else "<unknown>" |
michael@0 | 82 | |
michael@0 | 83 | def __eq__(self, other): |
michael@0 | 84 | return self._lexpos == other._lexpos and \ |
michael@0 | 85 | self._file == other._file |
michael@0 | 86 | |
michael@0 | 87 | def filename(self): |
michael@0 | 88 | return self._file |
michael@0 | 89 | |
michael@0 | 90 | def resolve(self): |
michael@0 | 91 | if self._line: |
michael@0 | 92 | return |
michael@0 | 93 | |
michael@0 | 94 | startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1 |
michael@0 | 95 | endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80) |
michael@0 | 96 | if endofline != -1: |
michael@0 | 97 | self._line = self._lexdata[startofline:endofline] |
michael@0 | 98 | else: |
michael@0 | 99 | self._line = self._lexdata[startofline:] |
michael@0 | 100 | self._colno = self._lexpos - startofline |
michael@0 | 101 | |
michael@0 | 102 | # Our line number seems to point to the start of self._lexdata |
michael@0 | 103 | self._lineno += self._lexdata.count('\n', 0, startofline) |
michael@0 | 104 | |
michael@0 | 105 | def get(self): |
michael@0 | 106 | self.resolve() |
michael@0 | 107 | return "%s line %s:%s" % (self._file, self._lineno, self._colno) |
michael@0 | 108 | |
michael@0 | 109 | def _pointerline(self): |
michael@0 | 110 | return " " * self._colno + "^" |
michael@0 | 111 | |
michael@0 | 112 | def __str__(self): |
michael@0 | 113 | self.resolve() |
michael@0 | 114 | return "%s line %s:%s\n%s\n%s" % (self._file, self._lineno, self._colno, |
michael@0 | 115 | self._line, self._pointerline()) |
michael@0 | 116 | |
michael@0 | 117 | class BuiltinLocation(object): |
michael@0 | 118 | def __init__(self, text): |
michael@0 | 119 | self.msg = text + "\n" |
michael@0 | 120 | |
michael@0 | 121 | def __eq__(self, other): |
michael@0 | 122 | return isinstance(other, BuiltinLocation) and \ |
michael@0 | 123 | self.msg == other.msg |
michael@0 | 124 | |
michael@0 | 125 | def filename(self): |
michael@0 | 126 | return '<builtin>' |
michael@0 | 127 | |
michael@0 | 128 | def resolve(self): |
michael@0 | 129 | pass |
michael@0 | 130 | |
michael@0 | 131 | def get(self): |
michael@0 | 132 | return self.msg |
michael@0 | 133 | |
michael@0 | 134 | def __str__(self): |
michael@0 | 135 | return self.get() |
michael@0 | 136 | |
michael@0 | 137 | |
michael@0 | 138 | # Data Model |
michael@0 | 139 | |
michael@0 | 140 | class IDLObject(object): |
michael@0 | 141 | def __init__(self, location): |
michael@0 | 142 | self.location = location |
michael@0 | 143 | self.userData = dict() |
michael@0 | 144 | |
michael@0 | 145 | def filename(self): |
michael@0 | 146 | return self.location.filename() |
michael@0 | 147 | |
michael@0 | 148 | def isInterface(self): |
michael@0 | 149 | return False |
michael@0 | 150 | |
michael@0 | 151 | def isEnum(self): |
michael@0 | 152 | return False |
michael@0 | 153 | |
michael@0 | 154 | def isCallback(self): |
michael@0 | 155 | return False |
michael@0 | 156 | |
michael@0 | 157 | def isType(self): |
michael@0 | 158 | return False |
michael@0 | 159 | |
michael@0 | 160 | def isDictionary(self): |
michael@0 | 161 | return False; |
michael@0 | 162 | |
michael@0 | 163 | def isUnion(self): |
michael@0 | 164 | return False |
michael@0 | 165 | |
michael@0 | 166 | def getUserData(self, key, default): |
michael@0 | 167 | return self.userData.get(key, default) |
michael@0 | 168 | |
michael@0 | 169 | def setUserData(self, key, value): |
michael@0 | 170 | self.userData[key] = value |
michael@0 | 171 | |
michael@0 | 172 | def addExtendedAttributes(self, attrs): |
michael@0 | 173 | assert False # Override me! |
michael@0 | 174 | |
michael@0 | 175 | def handleExtendedAttribute(self, attr): |
michael@0 | 176 | assert False # Override me! |
michael@0 | 177 | |
michael@0 | 178 | def _getDependentObjects(self): |
michael@0 | 179 | assert False # Override me! |
michael@0 | 180 | |
michael@0 | 181 | def getDeps(self, visited=None): |
michael@0 | 182 | """ Return a set of files that this object depends on. If any of |
michael@0 | 183 | these files are changed the parser needs to be rerun to regenerate |
michael@0 | 184 | a new IDLObject. |
michael@0 | 185 | |
michael@0 | 186 | The visited argument is a set of all the objects already visited. |
michael@0 | 187 | We must test to see if we are in it, and if so, do nothing. This |
michael@0 | 188 | prevents infinite recursion.""" |
michael@0 | 189 | |
michael@0 | 190 | # NB: We can't use visited=set() above because the default value is |
michael@0 | 191 | # evaluated when the def statement is evaluated, not when the function |
michael@0 | 192 | # is executed, so there would be one set for all invocations. |
michael@0 | 193 | if visited == None: |
michael@0 | 194 | visited = set() |
michael@0 | 195 | |
michael@0 | 196 | if self in visited: |
michael@0 | 197 | return set() |
michael@0 | 198 | |
michael@0 | 199 | visited.add(self) |
michael@0 | 200 | |
michael@0 | 201 | deps = set() |
michael@0 | 202 | if self.filename() != "<builtin>": |
michael@0 | 203 | deps.add(self.filename()) |
michael@0 | 204 | |
michael@0 | 205 | for d in self._getDependentObjects(): |
michael@0 | 206 | deps = deps.union(d.getDeps(visited)) |
michael@0 | 207 | |
michael@0 | 208 | return deps |
michael@0 | 209 | |
michael@0 | 210 | class IDLScope(IDLObject): |
michael@0 | 211 | def __init__(self, location, parentScope, identifier): |
michael@0 | 212 | IDLObject.__init__(self, location) |
michael@0 | 213 | |
michael@0 | 214 | self.parentScope = parentScope |
michael@0 | 215 | if identifier: |
michael@0 | 216 | assert isinstance(identifier, IDLIdentifier) |
michael@0 | 217 | self._name = identifier |
michael@0 | 218 | else: |
michael@0 | 219 | self._name = None |
michael@0 | 220 | |
michael@0 | 221 | self._dict = {} |
michael@0 | 222 | |
michael@0 | 223 | def __str__(self): |
michael@0 | 224 | return self.QName() |
michael@0 | 225 | |
michael@0 | 226 | def QName(self): |
michael@0 | 227 | if self._name: |
michael@0 | 228 | return self._name.QName() + "::" |
michael@0 | 229 | return "::" |
michael@0 | 230 | |
michael@0 | 231 | def ensureUnique(self, identifier, object): |
michael@0 | 232 | """ |
michael@0 | 233 | Ensure that there is at most one 'identifier' in scope ('self'). |
michael@0 | 234 | Note that object can be None. This occurs if we end up here for an |
michael@0 | 235 | interface type we haven't seen yet. |
michael@0 | 236 | """ |
michael@0 | 237 | assert isinstance(identifier, IDLUnresolvedIdentifier) |
michael@0 | 238 | assert not object or isinstance(object, IDLObjectWithIdentifier) |
michael@0 | 239 | assert not object or object.identifier == identifier |
michael@0 | 240 | |
michael@0 | 241 | if identifier.name in self._dict: |
michael@0 | 242 | if not object: |
michael@0 | 243 | return |
michael@0 | 244 | |
michael@0 | 245 | # ensureUnique twice with the same object is not allowed |
michael@0 | 246 | assert id(object) != id(self._dict[identifier.name]) |
michael@0 | 247 | |
michael@0 | 248 | replacement = self.resolveIdentifierConflict(self, identifier, |
michael@0 | 249 | self._dict[identifier.name], |
michael@0 | 250 | object) |
michael@0 | 251 | self._dict[identifier.name] = replacement |
michael@0 | 252 | return |
michael@0 | 253 | |
michael@0 | 254 | assert object |
michael@0 | 255 | |
michael@0 | 256 | self._dict[identifier.name] = object |
michael@0 | 257 | |
michael@0 | 258 | def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): |
michael@0 | 259 | if isinstance(originalObject, IDLExternalInterface) and \ |
michael@0 | 260 | isinstance(newObject, IDLExternalInterface) and \ |
michael@0 | 261 | originalObject.identifier.name == newObject.identifier.name: |
michael@0 | 262 | return originalObject |
michael@0 | 263 | |
michael@0 | 264 | if (isinstance(originalObject, IDLExternalInterface) or |
michael@0 | 265 | isinstance(newObject, IDLExternalInterface)): |
michael@0 | 266 | raise WebIDLError( |
michael@0 | 267 | "Name collision between " |
michael@0 | 268 | "interface declarations for identifier '%s' at '%s' and '%s'" |
michael@0 | 269 | % (identifier.name, |
michael@0 | 270 | originalObject.location, newObject.location), []) |
michael@0 | 271 | |
michael@0 | 272 | # We do the merging of overloads here as opposed to in IDLInterface |
michael@0 | 273 | # because we need to merge overloads of NamedConstructors and we need to |
michael@0 | 274 | # detect conflicts in those across interfaces. See also the comment in |
michael@0 | 275 | # IDLInterface.addExtendedAttributes for "NamedConstructor". |
michael@0 | 276 | if originalObject.tag == IDLInterfaceMember.Tags.Method and \ |
michael@0 | 277 | newObject.tag == IDLInterfaceMember.Tags.Method: |
michael@0 | 278 | return originalObject.addOverload(newObject) |
michael@0 | 279 | |
michael@0 | 280 | # Default to throwing, derived classes can override. |
michael@0 | 281 | conflictdesc = "\n\t%s at %s\n\t%s at %s" % \ |
michael@0 | 282 | (originalObject, originalObject.location, newObject, newObject.location) |
michael@0 | 283 | |
michael@0 | 284 | raise WebIDLError( |
michael@0 | 285 | "Multiple unresolvable definitions of identifier '%s' in scope '%s%s" |
michael@0 | 286 | % (identifier.name, str(self), conflictdesc), []) |
michael@0 | 287 | |
michael@0 | 288 | def _lookupIdentifier(self, identifier): |
michael@0 | 289 | return self._dict[identifier.name] |
michael@0 | 290 | |
michael@0 | 291 | def lookupIdentifier(self, identifier): |
michael@0 | 292 | assert isinstance(identifier, IDLIdentifier) |
michael@0 | 293 | assert identifier.scope == self |
michael@0 | 294 | return self._lookupIdentifier(identifier) |
michael@0 | 295 | |
michael@0 | 296 | class IDLIdentifier(IDLObject): |
michael@0 | 297 | def __init__(self, location, scope, name): |
michael@0 | 298 | IDLObject.__init__(self, location) |
michael@0 | 299 | |
michael@0 | 300 | self.name = name |
michael@0 | 301 | assert isinstance(scope, IDLScope) |
michael@0 | 302 | self.scope = scope |
michael@0 | 303 | |
michael@0 | 304 | def __str__(self): |
michael@0 | 305 | return self.QName() |
michael@0 | 306 | |
michael@0 | 307 | def QName(self): |
michael@0 | 308 | return self.scope.QName() + self.name |
michael@0 | 309 | |
michael@0 | 310 | def __hash__(self): |
michael@0 | 311 | return self.QName().__hash__() |
michael@0 | 312 | |
michael@0 | 313 | def __eq__(self, other): |
michael@0 | 314 | return self.QName() == other.QName() |
michael@0 | 315 | |
michael@0 | 316 | def object(self): |
michael@0 | 317 | return self.scope.lookupIdentifier(self) |
michael@0 | 318 | |
michael@0 | 319 | class IDLUnresolvedIdentifier(IDLObject): |
michael@0 | 320 | def __init__(self, location, name, allowDoubleUnderscore = False, |
michael@0 | 321 | allowForbidden = False): |
michael@0 | 322 | IDLObject.__init__(self, location) |
michael@0 | 323 | |
michael@0 | 324 | assert len(name) > 0 |
michael@0 | 325 | |
michael@0 | 326 | if name[:2] == "__" and name != "__content" and name != "___noSuchMethod__" and not allowDoubleUnderscore: |
michael@0 | 327 | raise WebIDLError("Identifiers beginning with __ are reserved", |
michael@0 | 328 | [location]) |
michael@0 | 329 | if name[0] == '_' and not allowDoubleUnderscore: |
michael@0 | 330 | name = name[1:] |
michael@0 | 331 | # TODO: Bug 872377, Restore "toJSON" to below list. |
michael@0 | 332 | # We sometimes need custom serialization, so allow toJSON for now. |
michael@0 | 333 | if (name in ["constructor", "toString"] and |
michael@0 | 334 | not allowForbidden): |
michael@0 | 335 | raise WebIDLError("Cannot use reserved identifier '%s'" % (name), |
michael@0 | 336 | [location]) |
michael@0 | 337 | |
michael@0 | 338 | self.name = name |
michael@0 | 339 | |
michael@0 | 340 | def __str__(self): |
michael@0 | 341 | return self.QName() |
michael@0 | 342 | |
michael@0 | 343 | def QName(self): |
michael@0 | 344 | return "<unresolved scope>::" + self.name |
michael@0 | 345 | |
michael@0 | 346 | def resolve(self, scope, object): |
michael@0 | 347 | assert isinstance(scope, IDLScope) |
michael@0 | 348 | assert not object or isinstance(object, IDLObjectWithIdentifier) |
michael@0 | 349 | assert not object or object.identifier == self |
michael@0 | 350 | |
michael@0 | 351 | scope.ensureUnique(self, object) |
michael@0 | 352 | |
michael@0 | 353 | identifier = IDLIdentifier(self.location, scope, self.name) |
michael@0 | 354 | if object: |
michael@0 | 355 | object.identifier = identifier |
michael@0 | 356 | return identifier |
michael@0 | 357 | |
michael@0 | 358 | def finish(self): |
michael@0 | 359 | assert False # Should replace with a resolved identifier first. |
michael@0 | 360 | |
michael@0 | 361 | class IDLObjectWithIdentifier(IDLObject): |
michael@0 | 362 | def __init__(self, location, parentScope, identifier): |
michael@0 | 363 | IDLObject.__init__(self, location) |
michael@0 | 364 | |
michael@0 | 365 | assert isinstance(identifier, IDLUnresolvedIdentifier) |
michael@0 | 366 | |
michael@0 | 367 | self.identifier = identifier |
michael@0 | 368 | |
michael@0 | 369 | if parentScope: |
michael@0 | 370 | self.resolve(parentScope) |
michael@0 | 371 | |
michael@0 | 372 | self.treatNullAs = "Default" |
michael@0 | 373 | |
michael@0 | 374 | def resolve(self, parentScope): |
michael@0 | 375 | assert isinstance(parentScope, IDLScope) |
michael@0 | 376 | assert isinstance(self.identifier, IDLUnresolvedIdentifier) |
michael@0 | 377 | self.identifier.resolve(parentScope, self) |
michael@0 | 378 | |
michael@0 | 379 | def checkForStringHandlingExtendedAttributes(self, attrs, |
michael@0 | 380 | isDictionaryMember=False, |
michael@0 | 381 | isOptional=False): |
michael@0 | 382 | """ |
michael@0 | 383 | A helper function to deal with TreatNullAs. Returns the list |
michael@0 | 384 | of attrs it didn't handle itself. |
michael@0 | 385 | """ |
michael@0 | 386 | assert isinstance(self, IDLArgument) or isinstance(self, IDLAttribute) |
michael@0 | 387 | unhandledAttrs = list() |
michael@0 | 388 | for attr in attrs: |
michael@0 | 389 | if not attr.hasValue(): |
michael@0 | 390 | unhandledAttrs.append(attr) |
michael@0 | 391 | continue |
michael@0 | 392 | |
michael@0 | 393 | identifier = attr.identifier() |
michael@0 | 394 | value = attr.value() |
michael@0 | 395 | if identifier == "TreatNullAs": |
michael@0 | 396 | if not self.type.isDOMString() or self.type.nullable(): |
michael@0 | 397 | raise WebIDLError("[TreatNullAs] is only allowed on " |
michael@0 | 398 | "arguments or attributes whose type is " |
michael@0 | 399 | "DOMString", |
michael@0 | 400 | [self.location]) |
michael@0 | 401 | if isDictionaryMember: |
michael@0 | 402 | raise WebIDLError("[TreatNullAs] is not allowed for " |
michael@0 | 403 | "dictionary members", [self.location]) |
michael@0 | 404 | if value != 'EmptyString': |
michael@0 | 405 | raise WebIDLError("[TreatNullAs] must take the identifier " |
michael@0 | 406 | "'EmptyString', not '%s'" % value, |
michael@0 | 407 | [self.location]) |
michael@0 | 408 | self.treatNullAs = value |
michael@0 | 409 | else: |
michael@0 | 410 | unhandledAttrs.append(attr) |
michael@0 | 411 | |
michael@0 | 412 | return unhandledAttrs |
michael@0 | 413 | |
michael@0 | 414 | class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope): |
michael@0 | 415 | def __init__(self, location, parentScope, identifier): |
michael@0 | 416 | assert isinstance(identifier, IDLUnresolvedIdentifier) |
michael@0 | 417 | |
michael@0 | 418 | IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier) |
michael@0 | 419 | IDLScope.__init__(self, location, parentScope, self.identifier) |
michael@0 | 420 | |
michael@0 | 421 | class IDLIdentifierPlaceholder(IDLObjectWithIdentifier): |
michael@0 | 422 | def __init__(self, location, identifier): |
michael@0 | 423 | assert isinstance(identifier, IDLUnresolvedIdentifier) |
michael@0 | 424 | IDLObjectWithIdentifier.__init__(self, location, None, identifier) |
michael@0 | 425 | |
michael@0 | 426 | def finish(self, scope): |
michael@0 | 427 | try: |
michael@0 | 428 | scope._lookupIdentifier(self.identifier) |
michael@0 | 429 | except: |
michael@0 | 430 | raise WebIDLError("Unresolved type '%s'." % self.identifier, |
michael@0 | 431 | [self.location]) |
michael@0 | 432 | |
michael@0 | 433 | obj = self.identifier.resolve(scope, None) |
michael@0 | 434 | return scope.lookupIdentifier(obj) |
michael@0 | 435 | |
michael@0 | 436 | class IDLExternalInterface(IDLObjectWithIdentifier): |
michael@0 | 437 | def __init__(self, location, parentScope, identifier): |
michael@0 | 438 | assert isinstance(identifier, IDLUnresolvedIdentifier) |
michael@0 | 439 | assert isinstance(parentScope, IDLScope) |
michael@0 | 440 | self.parent = None |
michael@0 | 441 | IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier) |
michael@0 | 442 | IDLObjectWithIdentifier.resolve(self, parentScope) |
michael@0 | 443 | |
michael@0 | 444 | def finish(self, scope): |
michael@0 | 445 | pass |
michael@0 | 446 | |
michael@0 | 447 | def validate(self): |
michael@0 | 448 | pass |
michael@0 | 449 | |
michael@0 | 450 | def isExternal(self): |
michael@0 | 451 | return True |
michael@0 | 452 | |
michael@0 | 453 | def isInterface(self): |
michael@0 | 454 | return True |
michael@0 | 455 | |
michael@0 | 456 | def isConsequential(self): |
michael@0 | 457 | return False |
michael@0 | 458 | |
michael@0 | 459 | def addExtendedAttributes(self, attrs): |
michael@0 | 460 | assert len(attrs) == 0 |
michael@0 | 461 | |
michael@0 | 462 | def resolve(self, parentScope): |
michael@0 | 463 | pass |
michael@0 | 464 | |
michael@0 | 465 | def getJSImplementation(self): |
michael@0 | 466 | return None |
michael@0 | 467 | |
michael@0 | 468 | def isJSImplemented(self): |
michael@0 | 469 | return False |
michael@0 | 470 | |
michael@0 | 471 | def getNavigatorProperty(self): |
michael@0 | 472 | return None |
michael@0 | 473 | |
michael@0 | 474 | def _getDependentObjects(self): |
michael@0 | 475 | return set() |
michael@0 | 476 | |
michael@0 | 477 | class IDLInterface(IDLObjectWithScope): |
michael@0 | 478 | def __init__(self, location, parentScope, name, parent, members, |
michael@0 | 479 | isPartial): |
michael@0 | 480 | assert isinstance(parentScope, IDLScope) |
michael@0 | 481 | assert isinstance(name, IDLUnresolvedIdentifier) |
michael@0 | 482 | assert not isPartial or not parent |
michael@0 | 483 | |
michael@0 | 484 | self.parent = None |
michael@0 | 485 | self._callback = False |
michael@0 | 486 | self._finished = False |
michael@0 | 487 | self.members = [] |
michael@0 | 488 | # namedConstructors needs deterministic ordering because bindings code |
michael@0 | 489 | # outputs the constructs in the order that namedConstructors enumerates |
michael@0 | 490 | # them. |
michael@0 | 491 | self.namedConstructors = list() |
michael@0 | 492 | self.implementedInterfaces = set() |
michael@0 | 493 | self._consequential = False |
michael@0 | 494 | self._isPartial = True |
michael@0 | 495 | # self.interfacesBasedOnSelf is the set of interfaces that inherit from |
michael@0 | 496 | # self or have self as a consequential interface, including self itself. |
michael@0 | 497 | # Used for distinguishability checking. |
michael@0 | 498 | self.interfacesBasedOnSelf = set([self]) |
michael@0 | 499 | # self.interfacesImplementingSelf is the set of interfaces that directly |
michael@0 | 500 | # have self as a consequential interface |
michael@0 | 501 | self.interfacesImplementingSelf = set() |
michael@0 | 502 | self._hasChildInterfaces = False |
michael@0 | 503 | self._isOnGlobalProtoChain = False |
michael@0 | 504 | # Tracking of the number of reserved slots we need for our |
michael@0 | 505 | # members and those of ancestor interfaces. |
michael@0 | 506 | self.totalMembersInSlots = 0 |
michael@0 | 507 | # Tracking of the number of own own members we have in slots |
michael@0 | 508 | self._ownMembersInSlots = 0 |
michael@0 | 509 | |
michael@0 | 510 | IDLObjectWithScope.__init__(self, location, parentScope, name) |
michael@0 | 511 | |
michael@0 | 512 | if not isPartial: |
michael@0 | 513 | self.setNonPartial(location, parent, members) |
michael@0 | 514 | else: |
michael@0 | 515 | # Just remember our members for now |
michael@0 | 516 | self.members = members |
michael@0 | 517 | |
michael@0 | 518 | def __str__(self): |
michael@0 | 519 | return "Interface '%s'" % self.identifier.name |
michael@0 | 520 | |
michael@0 | 521 | def ctor(self): |
michael@0 | 522 | identifier = IDLUnresolvedIdentifier(self.location, "constructor", |
michael@0 | 523 | allowForbidden=True) |
michael@0 | 524 | try: |
michael@0 | 525 | return self._lookupIdentifier(identifier) |
michael@0 | 526 | except: |
michael@0 | 527 | return None |
michael@0 | 528 | |
michael@0 | 529 | def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): |
michael@0 | 530 | assert isinstance(scope, IDLScope) |
michael@0 | 531 | assert isinstance(originalObject, IDLInterfaceMember) |
michael@0 | 532 | assert isinstance(newObject, IDLInterfaceMember) |
michael@0 | 533 | |
michael@0 | 534 | retval = IDLScope.resolveIdentifierConflict(self, scope, identifier, |
michael@0 | 535 | originalObject, newObject) |
michael@0 | 536 | |
michael@0 | 537 | # Might be a ctor, which isn't in self.members |
michael@0 | 538 | if newObject in self.members: |
michael@0 | 539 | self.members.remove(newObject) |
michael@0 | 540 | return retval |
michael@0 | 541 | |
michael@0 | 542 | def finish(self, scope): |
michael@0 | 543 | if self._finished: |
michael@0 | 544 | return |
michael@0 | 545 | |
michael@0 | 546 | self._finished = True |
michael@0 | 547 | |
michael@0 | 548 | if self._isPartial: |
michael@0 | 549 | raise WebIDLError("Interface %s does not have a non-partial " |
michael@0 | 550 | "declaration" % self.identifier.name, |
michael@0 | 551 | [self.location]) |
michael@0 | 552 | |
michael@0 | 553 | assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder) |
michael@0 | 554 | parent = self.parent.finish(scope) if self.parent else None |
michael@0 | 555 | if parent and isinstance(parent, IDLExternalInterface): |
michael@0 | 556 | raise WebIDLError("%s inherits from %s which does not have " |
michael@0 | 557 | "a definition" % |
michael@0 | 558 | (self.identifier.name, |
michael@0 | 559 | self.parent.identifier.name), |
michael@0 | 560 | [self.location]) |
michael@0 | 561 | assert not parent or isinstance(parent, IDLInterface) |
michael@0 | 562 | |
michael@0 | 563 | self.parent = parent |
michael@0 | 564 | |
michael@0 | 565 | assert iter(self.members) |
michael@0 | 566 | |
michael@0 | 567 | if self.parent: |
michael@0 | 568 | self.parent.finish(scope) |
michael@0 | 569 | |
michael@0 | 570 | self.parent._hasChildInterfaces = True |
michael@0 | 571 | |
michael@0 | 572 | self.totalMembersInSlots = self.parent.totalMembersInSlots |
michael@0 | 573 | |
michael@0 | 574 | # Interfaces with [Global] must not have anything inherit from them |
michael@0 | 575 | if self.parent.getExtendedAttribute("Global"): |
michael@0 | 576 | # Note: This is not a self.parent.isOnGlobalProtoChain() check |
michael@0 | 577 | # because ancestors of a [Global] interface can have other |
michael@0 | 578 | # descendants. |
michael@0 | 579 | raise WebIDLError("[Global] interface has another interface " |
michael@0 | 580 | "inheriting from it", |
michael@0 | 581 | [self.location, self.parent.location]) |
michael@0 | 582 | |
michael@0 | 583 | # Callbacks must not inherit from non-callbacks or inherit from |
michael@0 | 584 | # anything that has consequential interfaces. |
michael@0 | 585 | # XXXbz Can non-callbacks inherit from callbacks? Spec issue pending. |
michael@0 | 586 | # XXXbz Can callbacks have consequential interfaces? Spec issue pending |
michael@0 | 587 | if self.isCallback(): |
michael@0 | 588 | if not self.parent.isCallback(): |
michael@0 | 589 | raise WebIDLError("Callback interface %s inheriting from " |
michael@0 | 590 | "non-callback interface %s" % |
michael@0 | 591 | (self.identifier.name, |
michael@0 | 592 | self.parent.identifier.name), |
michael@0 | 593 | [self.location, self.parent.location]) |
michael@0 | 594 | elif self.parent.isCallback(): |
michael@0 | 595 | raise WebIDLError("Non-callback interface %s inheriting from " |
michael@0 | 596 | "callback interface %s" % |
michael@0 | 597 | (self.identifier.name, |
michael@0 | 598 | self.parent.identifier.name), |
michael@0 | 599 | [self.location, self.parent.location]) |
michael@0 | 600 | |
michael@0 | 601 | for iface in self.implementedInterfaces: |
michael@0 | 602 | iface.finish(scope) |
michael@0 | 603 | |
michael@0 | 604 | cycleInGraph = self.findInterfaceLoopPoint(self) |
michael@0 | 605 | if cycleInGraph: |
michael@0 | 606 | raise WebIDLError("Interface %s has itself as ancestor or " |
michael@0 | 607 | "implemented interface" % self.identifier.name, |
michael@0 | 608 | [self.location, cycleInGraph.location]) |
michael@0 | 609 | |
michael@0 | 610 | if self.isCallback(): |
michael@0 | 611 | # "implements" should have made sure we have no |
michael@0 | 612 | # consequential interfaces. |
michael@0 | 613 | assert len(self.getConsequentialInterfaces()) == 0 |
michael@0 | 614 | # And that we're not consequential. |
michael@0 | 615 | assert not self.isConsequential() |
michael@0 | 616 | |
michael@0 | 617 | # Now resolve() and finish() our members before importing the |
michael@0 | 618 | # ones from our implemented interfaces. |
michael@0 | 619 | |
michael@0 | 620 | # resolve() will modify self.members, so we need to iterate |
michael@0 | 621 | # over a copy of the member list here. |
michael@0 | 622 | for member in list(self.members): |
michael@0 | 623 | member.resolve(self) |
michael@0 | 624 | |
michael@0 | 625 | for member in self.members: |
michael@0 | 626 | member.finish(scope) |
michael@0 | 627 | |
michael@0 | 628 | ctor = self.ctor() |
michael@0 | 629 | if ctor is not None: |
michael@0 | 630 | ctor.finish(scope) |
michael@0 | 631 | |
michael@0 | 632 | for ctor in self.namedConstructors: |
michael@0 | 633 | ctor.finish(scope) |
michael@0 | 634 | |
michael@0 | 635 | # Make a copy of our member list, so things that implement us |
michael@0 | 636 | # can get those without all the stuff we implement ourselves |
michael@0 | 637 | # admixed. |
michael@0 | 638 | self.originalMembers = list(self.members) |
michael@0 | 639 | |
michael@0 | 640 | # Import everything from our consequential interfaces into |
michael@0 | 641 | # self.members. Sort our consequential interfaces by name |
michael@0 | 642 | # just so we have a consistent order. |
michael@0 | 643 | for iface in sorted(self.getConsequentialInterfaces(), |
michael@0 | 644 | cmp=cmp, |
michael@0 | 645 | key=lambda x: x.identifier.name): |
michael@0 | 646 | # Flag the interface as being someone's consequential interface |
michael@0 | 647 | iface.setIsConsequentialInterfaceOf(self) |
michael@0 | 648 | additionalMembers = iface.originalMembers; |
michael@0 | 649 | for additionalMember in additionalMembers: |
michael@0 | 650 | for member in self.members: |
michael@0 | 651 | if additionalMember.identifier.name == member.identifier.name: |
michael@0 | 652 | raise WebIDLError( |
michael@0 | 653 | "Multiple definitions of %s on %s coming from 'implements' statements" % |
michael@0 | 654 | (member.identifier.name, self), |
michael@0 | 655 | [additionalMember.location, member.location]) |
michael@0 | 656 | self.members.extend(additionalMembers) |
michael@0 | 657 | iface.interfacesImplementingSelf.add(self) |
michael@0 | 658 | |
michael@0 | 659 | for ancestor in self.getInheritedInterfaces(): |
michael@0 | 660 | ancestor.interfacesBasedOnSelf.add(self) |
michael@0 | 661 | for ancestorConsequential in ancestor.getConsequentialInterfaces(): |
michael@0 | 662 | ancestorConsequential.interfacesBasedOnSelf.add(self) |
michael@0 | 663 | |
michael@0 | 664 | for member in self.members: |
michael@0 | 665 | if (member.isAttr() and member.isUnforgeable() and |
michael@0 | 666 | not hasattr(member, "originatingInterface")): |
michael@0 | 667 | member.originatingInterface = self |
michael@0 | 668 | |
michael@0 | 669 | # Compute slot indices for our members before we pull in |
michael@0 | 670 | # unforgeable members from our parent. |
michael@0 | 671 | for member in self.members: |
michael@0 | 672 | if (member.isAttr() and |
michael@0 | 673 | (member.getExtendedAttribute("StoreInSlot") or |
michael@0 | 674 | member.getExtendedAttribute("Cached"))): |
michael@0 | 675 | member.slotIndex = self.totalMembersInSlots |
michael@0 | 676 | self.totalMembersInSlots += 1 |
michael@0 | 677 | if member.getExtendedAttribute("StoreInSlot"): |
michael@0 | 678 | self._ownMembersInSlots += 1 |
michael@0 | 679 | |
michael@0 | 680 | if self.parent: |
michael@0 | 681 | # Make sure we don't shadow any of the [Unforgeable] attributes on |
michael@0 | 682 | # our ancestor interfaces. We don't have to worry about |
michael@0 | 683 | # consequential interfaces here, because those have already been |
michael@0 | 684 | # imported into the relevant .members lists. And we don't have to |
michael@0 | 685 | # worry about anything other than our parent, because it has already |
michael@0 | 686 | # imported its ancestors unforgeable attributes into its member |
michael@0 | 687 | # list. |
michael@0 | 688 | for unforgeableAttr in (attr for attr in self.parent.members if |
michael@0 | 689 | attr.isAttr() and not attr.isStatic() and |
michael@0 | 690 | attr.isUnforgeable()): |
michael@0 | 691 | shadows = [ m for m in self.members if |
michael@0 | 692 | (m.isAttr() or m.isMethod()) and |
michael@0 | 693 | not m.isStatic() and |
michael@0 | 694 | m.identifier.name == unforgeableAttr.identifier.name ] |
michael@0 | 695 | if len(shadows) != 0: |
michael@0 | 696 | locs = [unforgeableAttr.location] + [ s.location for s |
michael@0 | 697 | in shadows ] |
michael@0 | 698 | raise WebIDLError("Interface %s shadows [Unforgeable] " |
michael@0 | 699 | "members of %s" % |
michael@0 | 700 | (self.identifier.name, |
michael@0 | 701 | ancestor.identifier.name), |
michael@0 | 702 | locs) |
michael@0 | 703 | # And now just stick it in our members, since we won't be |
michael@0 | 704 | # inheriting this down the proto chain. If we really cared we |
michael@0 | 705 | # could try to do something where we set up the unforgeable |
michael@0 | 706 | # attributes of ancestor interfaces, with their corresponding |
michael@0 | 707 | # getters, on our interface, but that gets pretty complicated |
michael@0 | 708 | # and seems unnecessary. |
michael@0 | 709 | self.members.append(unforgeableAttr) |
michael@0 | 710 | |
michael@0 | 711 | # Ensure that there's at most one of each {named,indexed} |
michael@0 | 712 | # {getter,setter,creator,deleter}, at most one stringifier, |
michael@0 | 713 | # and at most one legacycaller. Note that this last is not |
michael@0 | 714 | # quite per spec, but in practice no one overloads |
michael@0 | 715 | # legacycallers. |
michael@0 | 716 | specialMembersSeen = {} |
michael@0 | 717 | for member in self.members: |
michael@0 | 718 | if not member.isMethod(): |
michael@0 | 719 | continue |
michael@0 | 720 | |
michael@0 | 721 | if member.isGetter(): |
michael@0 | 722 | memberType = "getters" |
michael@0 | 723 | elif member.isSetter(): |
michael@0 | 724 | memberType = "setters" |
michael@0 | 725 | elif member.isCreator(): |
michael@0 | 726 | memberType = "creators" |
michael@0 | 727 | elif member.isDeleter(): |
michael@0 | 728 | memberType = "deleters" |
michael@0 | 729 | elif member.isStringifier(): |
michael@0 | 730 | memberType = "stringifiers" |
michael@0 | 731 | elif member.isJsonifier(): |
michael@0 | 732 | memberType = "jsonifiers" |
michael@0 | 733 | elif member.isLegacycaller(): |
michael@0 | 734 | memberType = "legacycallers" |
michael@0 | 735 | else: |
michael@0 | 736 | continue |
michael@0 | 737 | |
michael@0 | 738 | if (memberType != "stringifiers" and memberType != "legacycallers" and |
michael@0 | 739 | memberType != "jsonifiers"): |
michael@0 | 740 | if member.isNamed(): |
michael@0 | 741 | memberType = "named " + memberType |
michael@0 | 742 | else: |
michael@0 | 743 | assert member.isIndexed() |
michael@0 | 744 | memberType = "indexed " + memberType |
michael@0 | 745 | |
michael@0 | 746 | if memberType in specialMembersSeen: |
michael@0 | 747 | raise WebIDLError("Multiple " + memberType + " on %s" % (self), |
michael@0 | 748 | [self.location, |
michael@0 | 749 | specialMembersSeen[memberType].location, |
michael@0 | 750 | member.location]) |
michael@0 | 751 | |
michael@0 | 752 | specialMembersSeen[memberType] = member |
michael@0 | 753 | |
michael@0 | 754 | if self._isOnGlobalProtoChain: |
michael@0 | 755 | # Make sure we have no named setters, creators, or deleters |
michael@0 | 756 | for memberType in ["setter", "creator", "deleter"]: |
michael@0 | 757 | memberId = "named " + memberType + "s" |
michael@0 | 758 | if memberId in specialMembersSeen: |
michael@0 | 759 | raise WebIDLError("Interface with [Global] has a named %s" % |
michael@0 | 760 | memberType, |
michael@0 | 761 | [self.location, |
michael@0 | 762 | specialMembersSeen[memberId].location]) |
michael@0 | 763 | # Make sure we're not [OverrideBuiltins] |
michael@0 | 764 | if self.getExtendedAttribute("OverrideBuiltins"): |
michael@0 | 765 | raise WebIDLError("Interface with [Global] also has " |
michael@0 | 766 | "[OverrideBuiltins]", |
michael@0 | 767 | [self.location]) |
michael@0 | 768 | # Mark all of our ancestors as being on the global's proto chain too |
michael@0 | 769 | parent = self.parent |
michael@0 | 770 | while parent: |
michael@0 | 771 | # Must not inherit from an interface with [OverrideBuiltins] |
michael@0 | 772 | if parent.getExtendedAttribute("OverrideBuiltins"): |
michael@0 | 773 | raise WebIDLError("Interface with [Global] inherits from " |
michael@0 | 774 | "interface with [OverrideBuiltins]", |
michael@0 | 775 | [self.location, parent.location]) |
michael@0 | 776 | parent._isOnGlobalProtoChain = True |
michael@0 | 777 | parent = parent.parent |
michael@0 | 778 | |
michael@0 | 779 | def validate(self): |
michael@0 | 780 | for member in self.members: |
michael@0 | 781 | member.validate() |
michael@0 | 782 | |
michael@0 | 783 | # Check that PutForwards refers to another attribute and that no |
michael@0 | 784 | # cycles exist in forwarded assignments. |
michael@0 | 785 | if member.isAttr(): |
michael@0 | 786 | iface = self |
michael@0 | 787 | attr = member |
michael@0 | 788 | putForwards = attr.getExtendedAttribute("PutForwards") |
michael@0 | 789 | if putForwards and self.isCallback(): |
michael@0 | 790 | raise WebIDLError("[PutForwards] used on an attribute " |
michael@0 | 791 | "on interface %s which is a callback " |
michael@0 | 792 | "interface" % self.identifier.name, |
michael@0 | 793 | [self.location, member.location]) |
michael@0 | 794 | |
michael@0 | 795 | while putForwards is not None: |
michael@0 | 796 | forwardIface = attr.type.unroll().inner |
michael@0 | 797 | fowardAttr = None |
michael@0 | 798 | |
michael@0 | 799 | for forwardedMember in forwardIface.members: |
michael@0 | 800 | if (not forwardedMember.isAttr() or |
michael@0 | 801 | forwardedMember.identifier.name != putForwards[0]): |
michael@0 | 802 | continue |
michael@0 | 803 | if forwardedMember == member: |
michael@0 | 804 | raise WebIDLError("Cycle detected in forwarded " |
michael@0 | 805 | "assignments for attribute %s on " |
michael@0 | 806 | "%s" % |
michael@0 | 807 | (member.identifier.name, self), |
michael@0 | 808 | [member.location]) |
michael@0 | 809 | fowardAttr = forwardedMember |
michael@0 | 810 | break |
michael@0 | 811 | |
michael@0 | 812 | if fowardAttr is None: |
michael@0 | 813 | raise WebIDLError("Attribute %s on %s forwards to " |
michael@0 | 814 | "missing attribute %s" % |
michael@0 | 815 | (attr.identifier.name, iface, putForwards), |
michael@0 | 816 | [attr.location]) |
michael@0 | 817 | |
michael@0 | 818 | iface = forwardIface |
michael@0 | 819 | attr = fowardAttr |
michael@0 | 820 | putForwards = attr.getExtendedAttribute("PutForwards") |
michael@0 | 821 | |
michael@0 | 822 | |
michael@0 | 823 | def isInterface(self): |
michael@0 | 824 | return True |
michael@0 | 825 | |
michael@0 | 826 | def isExternal(self): |
michael@0 | 827 | return False |
michael@0 | 828 | |
michael@0 | 829 | def setIsConsequentialInterfaceOf(self, other): |
michael@0 | 830 | self._consequential = True |
michael@0 | 831 | self.interfacesBasedOnSelf.add(other) |
michael@0 | 832 | |
michael@0 | 833 | def isConsequential(self): |
michael@0 | 834 | return self._consequential |
michael@0 | 835 | |
michael@0 | 836 | def setCallback(self, value): |
michael@0 | 837 | self._callback = value |
michael@0 | 838 | |
michael@0 | 839 | def isCallback(self): |
michael@0 | 840 | return self._callback |
michael@0 | 841 | |
michael@0 | 842 | def isSingleOperationInterface(self): |
michael@0 | 843 | assert self.isCallback() or self.isJSImplemented() |
michael@0 | 844 | return ( |
michael@0 | 845 | # JS-implemented things should never need the |
michael@0 | 846 | # this-handling weirdness of single-operation interfaces. |
michael@0 | 847 | not self.isJSImplemented() and |
michael@0 | 848 | # Not inheriting from another interface |
michael@0 | 849 | not self.parent and |
michael@0 | 850 | # No consequential interfaces |
michael@0 | 851 | len(self.getConsequentialInterfaces()) == 0 and |
michael@0 | 852 | # No attributes of any kinds |
michael@0 | 853 | not any(m.isAttr() for m in self.members) and |
michael@0 | 854 | # There is at least one regular operation, and all regular |
michael@0 | 855 | # operations have the same identifier |
michael@0 | 856 | len(set(m.identifier.name for m in self.members if |
michael@0 | 857 | m.isMethod() and not m.isStatic())) == 1) |
michael@0 | 858 | |
michael@0 | 859 | def inheritanceDepth(self): |
michael@0 | 860 | depth = 0 |
michael@0 | 861 | parent = self.parent |
michael@0 | 862 | while parent: |
michael@0 | 863 | depth = depth + 1 |
michael@0 | 864 | parent = parent.parent |
michael@0 | 865 | return depth |
michael@0 | 866 | |
michael@0 | 867 | def hasConstants(self): |
michael@0 | 868 | return any(m.isConst() for m in self.members) |
michael@0 | 869 | |
michael@0 | 870 | def hasInterfaceObject(self): |
michael@0 | 871 | if self.isCallback(): |
michael@0 | 872 | return self.hasConstants() |
michael@0 | 873 | return not hasattr(self, "_noInterfaceObject") |
michael@0 | 874 | |
michael@0 | 875 | def hasInterfacePrototypeObject(self): |
michael@0 | 876 | return not self.isCallback() and self.getUserData('hasConcreteDescendant', False) |
michael@0 | 877 | |
michael@0 | 878 | def addExtendedAttributes(self, attrs): |
michael@0 | 879 | self._extendedAttrDict = {} |
michael@0 | 880 | for attr in attrs: |
michael@0 | 881 | identifier = attr.identifier() |
michael@0 | 882 | |
michael@0 | 883 | # Special cased attrs |
michael@0 | 884 | if identifier == "TreatNonCallableAsNull": |
michael@0 | 885 | raise WebIDLError("TreatNonCallableAsNull cannot be specified on interfaces", |
michael@0 | 886 | [attr.location, self.location]) |
michael@0 | 887 | if identifier == "TreatNonObjectAsNull": |
michael@0 | 888 | raise WebIDLError("TreatNonObjectAsNull cannot be specified on interfaces", |
michael@0 | 889 | [attr.location, self.location]) |
michael@0 | 890 | elif identifier == "NoInterfaceObject": |
michael@0 | 891 | if not attr.noArguments(): |
michael@0 | 892 | raise WebIDLError("[NoInterfaceObject] must take no arguments", |
michael@0 | 893 | [attr.location]) |
michael@0 | 894 | |
michael@0 | 895 | if self.ctor(): |
michael@0 | 896 | raise WebIDLError("Constructor and NoInterfaceObject are incompatible", |
michael@0 | 897 | [self.location]) |
michael@0 | 898 | |
michael@0 | 899 | self._noInterfaceObject = True |
michael@0 | 900 | elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor": |
michael@0 | 901 | if identifier == "Constructor" and not self.hasInterfaceObject(): |
michael@0 | 902 | raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", |
michael@0 | 903 | [self.location]) |
michael@0 | 904 | |
michael@0 | 905 | if identifier == "NamedConstructor" and not attr.hasValue(): |
michael@0 | 906 | raise WebIDLError("NamedConstructor must either take an identifier or take a named argument list", |
michael@0 | 907 | [attr.location]) |
michael@0 | 908 | |
michael@0 | 909 | if identifier == "ChromeConstructor" and not self.hasInterfaceObject(): |
michael@0 | 910 | raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", |
michael@0 | 911 | [self.location]) |
michael@0 | 912 | |
michael@0 | 913 | args = attr.args() if attr.hasArgs() else [] |
michael@0 | 914 | |
michael@0 | 915 | retType = IDLWrapperType(self.location, self) |
michael@0 | 916 | |
michael@0 | 917 | if identifier == "Constructor" or identifier == "ChromeConstructor": |
michael@0 | 918 | name = "constructor" |
michael@0 | 919 | allowForbidden = True |
michael@0 | 920 | else: |
michael@0 | 921 | name = attr.value() |
michael@0 | 922 | allowForbidden = False |
michael@0 | 923 | |
michael@0 | 924 | methodIdentifier = IDLUnresolvedIdentifier(self.location, name, |
michael@0 | 925 | allowForbidden=allowForbidden) |
michael@0 | 926 | |
michael@0 | 927 | method = IDLMethod(self.location, methodIdentifier, retType, |
michael@0 | 928 | args, static=True) |
michael@0 | 929 | # Constructors are always NewObject and are always |
michael@0 | 930 | # assumed to be able to throw (since there's no way to |
michael@0 | 931 | # indicate otherwise) and never have any other |
michael@0 | 932 | # extended attributes. |
michael@0 | 933 | method.addExtendedAttributes( |
michael@0 | 934 | [IDLExtendedAttribute(self.location, ("NewObject",)), |
michael@0 | 935 | IDLExtendedAttribute(self.location, ("Throws",))]) |
michael@0 | 936 | if identifier == "ChromeConstructor": |
michael@0 | 937 | method.addExtendedAttributes( |
michael@0 | 938 | [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) |
michael@0 | 939 | |
michael@0 | 940 | if identifier == "Constructor" or identifier == "ChromeConstructor": |
michael@0 | 941 | method.resolve(self) |
michael@0 | 942 | else: |
michael@0 | 943 | # We need to detect conflicts for NamedConstructors across |
michael@0 | 944 | # interfaces. We first call resolve on the parentScope, |
michael@0 | 945 | # which will merge all NamedConstructors with the same |
michael@0 | 946 | # identifier accross interfaces as overloads. |
michael@0 | 947 | method.resolve(self.parentScope) |
michael@0 | 948 | |
michael@0 | 949 | # Then we look up the identifier on the parentScope. If the |
michael@0 | 950 | # result is the same as the method we're adding then it |
michael@0 | 951 | # hasn't been added as an overload and it's the first time |
michael@0 | 952 | # we've encountered a NamedConstructor with that identifier. |
michael@0 | 953 | # If the result is not the same as the method we're adding |
michael@0 | 954 | # then it has been added as an overload and we need to check |
michael@0 | 955 | # whether the result is actually one of our existing |
michael@0 | 956 | # NamedConstructors. |
michael@0 | 957 | newMethod = self.parentScope.lookupIdentifier(method.identifier) |
michael@0 | 958 | if newMethod == method: |
michael@0 | 959 | self.namedConstructors.append(method) |
michael@0 | 960 | elif not newMethod in self.namedConstructors: |
michael@0 | 961 | raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface", |
michael@0 | 962 | [method.location, newMethod.location]) |
michael@0 | 963 | elif (identifier == "ArrayClass"): |
michael@0 | 964 | if not attr.noArguments(): |
michael@0 | 965 | raise WebIDLError("[ArrayClass] must take no arguments", |
michael@0 | 966 | [attr.location]) |
michael@0 | 967 | if self.parent: |
michael@0 | 968 | raise WebIDLError("[ArrayClass] must not be specified on " |
michael@0 | 969 | "an interface with inherited interfaces", |
michael@0 | 970 | [attr.location, self.location]) |
michael@0 | 971 | elif identifier == "Global": |
michael@0 | 972 | if not attr.noArguments(): |
michael@0 | 973 | raise WebIDLError("[Global] must take no arguments", |
michael@0 | 974 | [attr.location]) |
michael@0 | 975 | self._isOnGlobalProtoChain = True |
michael@0 | 976 | elif (identifier == "NeedNewResolve" or |
michael@0 | 977 | identifier == "OverrideBuiltins" or |
michael@0 | 978 | identifier == "ChromeOnly"): |
michael@0 | 979 | # Known extended attributes that do not take values |
michael@0 | 980 | if not attr.noArguments(): |
michael@0 | 981 | raise WebIDLError("[%s] must take no arguments" % identifier, |
michael@0 | 982 | [attr.location]) |
michael@0 | 983 | elif (identifier == "Pref" or |
michael@0 | 984 | identifier == "JSImplementation" or |
michael@0 | 985 | identifier == "HeaderFile" or |
michael@0 | 986 | identifier == "NavigatorProperty" or |
michael@0 | 987 | identifier == "AvailableIn" or |
michael@0 | 988 | identifier == "Func"): |
michael@0 | 989 | # Known extended attributes that take a string value |
michael@0 | 990 | if not attr.hasValue(): |
michael@0 | 991 | raise WebIDLError("[%s] must have a value" % identifier, |
michael@0 | 992 | [attr.location]) |
michael@0 | 993 | else: |
michael@0 | 994 | raise WebIDLError("Unknown extended attribute %s on interface" % identifier, |
michael@0 | 995 | [attr.location]) |
michael@0 | 996 | |
michael@0 | 997 | attrlist = attr.listValue() |
michael@0 | 998 | self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True |
michael@0 | 999 | |
michael@0 | 1000 | def addImplementedInterface(self, implementedInterface): |
michael@0 | 1001 | assert(isinstance(implementedInterface, IDLInterface)) |
michael@0 | 1002 | self.implementedInterfaces.add(implementedInterface) |
michael@0 | 1003 | |
michael@0 | 1004 | def getInheritedInterfaces(self): |
michael@0 | 1005 | """ |
michael@0 | 1006 | Returns a list of the interfaces this interface inherits from |
michael@0 | 1007 | (not including this interface itself). The list is in order |
michael@0 | 1008 | from most derived to least derived. |
michael@0 | 1009 | """ |
michael@0 | 1010 | assert(self._finished) |
michael@0 | 1011 | if not self.parent: |
michael@0 | 1012 | return [] |
michael@0 | 1013 | parentInterfaces = self.parent.getInheritedInterfaces() |
michael@0 | 1014 | parentInterfaces.insert(0, self.parent) |
michael@0 | 1015 | return parentInterfaces |
michael@0 | 1016 | |
michael@0 | 1017 | def getConsequentialInterfaces(self): |
michael@0 | 1018 | assert(self._finished) |
michael@0 | 1019 | # The interfaces we implement directly |
michael@0 | 1020 | consequentialInterfaces = set(self.implementedInterfaces) |
michael@0 | 1021 | |
michael@0 | 1022 | # And their inherited interfaces |
michael@0 | 1023 | for iface in self.implementedInterfaces: |
michael@0 | 1024 | consequentialInterfaces |= set(iface.getInheritedInterfaces()) |
michael@0 | 1025 | |
michael@0 | 1026 | # And now collect up the consequential interfaces of all of those |
michael@0 | 1027 | temp = set() |
michael@0 | 1028 | for iface in consequentialInterfaces: |
michael@0 | 1029 | temp |= iface.getConsequentialInterfaces() |
michael@0 | 1030 | |
michael@0 | 1031 | return consequentialInterfaces | temp |
michael@0 | 1032 | |
michael@0 | 1033 | def findInterfaceLoopPoint(self, otherInterface): |
michael@0 | 1034 | """ |
michael@0 | 1035 | Finds an interface, amongst our ancestors and consequential interfaces, |
michael@0 | 1036 | that inherits from otherInterface or implements otherInterface |
michael@0 | 1037 | directly. If there is no such interface, returns None. |
michael@0 | 1038 | """ |
michael@0 | 1039 | if self.parent: |
michael@0 | 1040 | if self.parent == otherInterface: |
michael@0 | 1041 | return self |
michael@0 | 1042 | loopPoint = self.parent.findInterfaceLoopPoint(otherInterface) |
michael@0 | 1043 | if loopPoint: |
michael@0 | 1044 | return loopPoint |
michael@0 | 1045 | if otherInterface in self.implementedInterfaces: |
michael@0 | 1046 | return self |
michael@0 | 1047 | for iface in self.implementedInterfaces: |
michael@0 | 1048 | loopPoint = iface.findInterfaceLoopPoint(otherInterface) |
michael@0 | 1049 | if loopPoint: |
michael@0 | 1050 | return loopPoint |
michael@0 | 1051 | return None |
michael@0 | 1052 | |
michael@0 | 1053 | def getExtendedAttribute(self, name): |
michael@0 | 1054 | return self._extendedAttrDict.get(name, None) |
michael@0 | 1055 | |
michael@0 | 1056 | def setNonPartial(self, location, parent, members): |
michael@0 | 1057 | assert not parent or isinstance(parent, IDLIdentifierPlaceholder) |
michael@0 | 1058 | if not self._isPartial: |
michael@0 | 1059 | raise WebIDLError("Two non-partial definitions for the " |
michael@0 | 1060 | "same interface", |
michael@0 | 1061 | [location, self.location]) |
michael@0 | 1062 | self._isPartial = False |
michael@0 | 1063 | # Now make it look like we were parsed at this new location, since |
michael@0 | 1064 | # that's the place where the interface is "really" defined |
michael@0 | 1065 | self.location = location |
michael@0 | 1066 | assert not self.parent |
michael@0 | 1067 | self.parent = parent |
michael@0 | 1068 | # Put the new members at the beginning |
michael@0 | 1069 | self.members = members + self.members |
michael@0 | 1070 | |
michael@0 | 1071 | def getJSImplementation(self): |
michael@0 | 1072 | classId = self.getExtendedAttribute("JSImplementation") |
michael@0 | 1073 | if not classId: |
michael@0 | 1074 | return classId |
michael@0 | 1075 | assert isinstance(classId, list) |
michael@0 | 1076 | assert len(classId) == 1 |
michael@0 | 1077 | return classId[0] |
michael@0 | 1078 | |
michael@0 | 1079 | def isJSImplemented(self): |
michael@0 | 1080 | return bool(self.getJSImplementation()) |
michael@0 | 1081 | |
michael@0 | 1082 | def getNavigatorProperty(self): |
michael@0 | 1083 | naviProp = self.getExtendedAttribute("NavigatorProperty") |
michael@0 | 1084 | if not naviProp: |
michael@0 | 1085 | return None |
michael@0 | 1086 | assert len(naviProp) == 1 |
michael@0 | 1087 | assert isinstance(naviProp, list) |
michael@0 | 1088 | assert len(naviProp[0]) != 0 |
michael@0 | 1089 | return naviProp[0] |
michael@0 | 1090 | |
michael@0 | 1091 | def hasChildInterfaces(self): |
michael@0 | 1092 | return self._hasChildInterfaces |
michael@0 | 1093 | |
michael@0 | 1094 | def isOnGlobalProtoChain(self): |
michael@0 | 1095 | return self._isOnGlobalProtoChain |
michael@0 | 1096 | |
michael@0 | 1097 | def _getDependentObjects(self): |
michael@0 | 1098 | deps = set(self.members) |
michael@0 | 1099 | deps.union(self.implementedInterfaces) |
michael@0 | 1100 | if self.parent: |
michael@0 | 1101 | deps.add(self.parent) |
michael@0 | 1102 | return deps |
michael@0 | 1103 | |
michael@0 | 1104 | def hasMembersInSlots(self): |
michael@0 | 1105 | return self._ownMembersInSlots != 0 |
michael@0 | 1106 | |
michael@0 | 1107 | class IDLDictionary(IDLObjectWithScope): |
michael@0 | 1108 | def __init__(self, location, parentScope, name, parent, members): |
michael@0 | 1109 | assert isinstance(parentScope, IDLScope) |
michael@0 | 1110 | assert isinstance(name, IDLUnresolvedIdentifier) |
michael@0 | 1111 | assert not parent or isinstance(parent, IDLIdentifierPlaceholder) |
michael@0 | 1112 | |
michael@0 | 1113 | self.parent = parent |
michael@0 | 1114 | self._finished = False |
michael@0 | 1115 | self.members = list(members) |
michael@0 | 1116 | |
michael@0 | 1117 | IDLObjectWithScope.__init__(self, location, parentScope, name) |
michael@0 | 1118 | |
michael@0 | 1119 | def __str__(self): |
michael@0 | 1120 | return "Dictionary '%s'" % self.identifier.name |
michael@0 | 1121 | |
michael@0 | 1122 | def isDictionary(self): |
michael@0 | 1123 | return True; |
michael@0 | 1124 | |
michael@0 | 1125 | def finish(self, scope): |
michael@0 | 1126 | if self._finished: |
michael@0 | 1127 | return |
michael@0 | 1128 | |
michael@0 | 1129 | self._finished = True |
michael@0 | 1130 | |
michael@0 | 1131 | if self.parent: |
michael@0 | 1132 | assert isinstance(self.parent, IDLIdentifierPlaceholder) |
michael@0 | 1133 | oldParent = self.parent |
michael@0 | 1134 | self.parent = self.parent.finish(scope) |
michael@0 | 1135 | if not isinstance(self.parent, IDLDictionary): |
michael@0 | 1136 | raise WebIDLError("Dictionary %s has parent that is not a dictionary" % |
michael@0 | 1137 | self.identifier.name, |
michael@0 | 1138 | [oldParent.location, self.parent.location]) |
michael@0 | 1139 | |
michael@0 | 1140 | # Make sure the parent resolves all its members before we start |
michael@0 | 1141 | # looking at them. |
michael@0 | 1142 | self.parent.finish(scope) |
michael@0 | 1143 | |
michael@0 | 1144 | for member in self.members: |
michael@0 | 1145 | member.resolve(self) |
michael@0 | 1146 | if not member.isComplete(): |
michael@0 | 1147 | member.complete(scope) |
michael@0 | 1148 | assert member.type.isComplete() |
michael@0 | 1149 | |
michael@0 | 1150 | # Members of a dictionary are sorted in lexicographic order |
michael@0 | 1151 | self.members.sort(cmp=cmp, key=lambda x: x.identifier.name) |
michael@0 | 1152 | |
michael@0 | 1153 | inheritedMembers = [] |
michael@0 | 1154 | ancestor = self.parent |
michael@0 | 1155 | while ancestor: |
michael@0 | 1156 | if ancestor == self: |
michael@0 | 1157 | raise WebIDLError("Dictionary %s has itself as an ancestor" % |
michael@0 | 1158 | self.identifier.name, |
michael@0 | 1159 | [self.identifier.location]) |
michael@0 | 1160 | inheritedMembers.extend(ancestor.members) |
michael@0 | 1161 | ancestor = ancestor.parent |
michael@0 | 1162 | |
michael@0 | 1163 | # Catch name duplication |
michael@0 | 1164 | for inheritedMember in inheritedMembers: |
michael@0 | 1165 | for member in self.members: |
michael@0 | 1166 | if member.identifier.name == inheritedMember.identifier.name: |
michael@0 | 1167 | raise WebIDLError("Dictionary %s has two members with name %s" % |
michael@0 | 1168 | (self.identifier.name, member.identifier.name), |
michael@0 | 1169 | [member.location, inheritedMember.location]) |
michael@0 | 1170 | |
michael@0 | 1171 | def validate(self): |
michael@0 | 1172 | def typeContainsDictionary(memberType, dictionary): |
michael@0 | 1173 | """ |
michael@0 | 1174 | Returns a tuple whose: |
michael@0 | 1175 | |
michael@0 | 1176 | - First element is a Boolean value indicating whether |
michael@0 | 1177 | memberType contains dictionary. |
michael@0 | 1178 | |
michael@0 | 1179 | - Second element is: |
michael@0 | 1180 | A list of locations that leads from the type that was passed in |
michael@0 | 1181 | the memberType argument, to the dictionary being validated, |
michael@0 | 1182 | if the boolean value in the first element is True. |
michael@0 | 1183 | |
michael@0 | 1184 | None, if the boolean value in the first element is False. |
michael@0 | 1185 | """ |
michael@0 | 1186 | |
michael@0 | 1187 | if (memberType.nullable() or |
michael@0 | 1188 | memberType.isArray() or |
michael@0 | 1189 | memberType.isSequence() or |
michael@0 | 1190 | memberType.isMozMap()): |
michael@0 | 1191 | return typeContainsDictionary(memberType.inner, dictionary) |
michael@0 | 1192 | |
michael@0 | 1193 | if memberType.isDictionary(): |
michael@0 | 1194 | if memberType.inner == dictionary: |
michael@0 | 1195 | return (True, [memberType.location]) |
michael@0 | 1196 | |
michael@0 | 1197 | (contains, locations) = dictionaryContainsDictionary(memberType.inner, \ |
michael@0 | 1198 | dictionary) |
michael@0 | 1199 | if contains: |
michael@0 | 1200 | return (True, [memberType.location] + locations) |
michael@0 | 1201 | |
michael@0 | 1202 | if memberType.isUnion(): |
michael@0 | 1203 | for member in memberType.flatMemberTypes: |
michael@0 | 1204 | (contains, locations) = typeContainsDictionary(member, dictionary) |
michael@0 | 1205 | if contains: |
michael@0 | 1206 | return (True, locations) |
michael@0 | 1207 | |
michael@0 | 1208 | return (False, None) |
michael@0 | 1209 | |
michael@0 | 1210 | def dictionaryContainsDictionary(dictMember, dictionary): |
michael@0 | 1211 | for member in dictMember.members: |
michael@0 | 1212 | (contains, locations) = typeContainsDictionary(member.type, dictionary) |
michael@0 | 1213 | if contains: |
michael@0 | 1214 | return (True, [member.location] + locations) |
michael@0 | 1215 | |
michael@0 | 1216 | if dictMember.parent: |
michael@0 | 1217 | if dictMember.parent == dictionary: |
michael@0 | 1218 | return (True, [dictMember.location]) |
michael@0 | 1219 | else: |
michael@0 | 1220 | (contains, locations) = dictionaryContainsDictionary(dictMember.parent, dictionary) |
michael@0 | 1221 | if contains: |
michael@0 | 1222 | return (True, [dictMember.location] + locations) |
michael@0 | 1223 | |
michael@0 | 1224 | return (False, None) |
michael@0 | 1225 | |
michael@0 | 1226 | for member in self.members: |
michael@0 | 1227 | if member.type.isDictionary() and member.type.nullable(): |
michael@0 | 1228 | raise WebIDLError("Dictionary %s has member with nullable " |
michael@0 | 1229 | "dictionary type" % self.identifier.name, |
michael@0 | 1230 | [member.location]) |
michael@0 | 1231 | (contains, locations) = typeContainsDictionary(member.type, self) |
michael@0 | 1232 | if contains: |
michael@0 | 1233 | raise WebIDLError("Dictionary %s has member with itself as type." % |
michael@0 | 1234 | self.identifier.name, |
michael@0 | 1235 | [member.location] + locations) |
michael@0 | 1236 | |
michael@0 | 1237 | def addExtendedAttributes(self, attrs): |
michael@0 | 1238 | assert len(attrs) == 0 |
michael@0 | 1239 | |
michael@0 | 1240 | def _getDependentObjects(self): |
michael@0 | 1241 | deps = set(self.members) |
michael@0 | 1242 | if (self.parent): |
michael@0 | 1243 | deps.add(self.parent) |
michael@0 | 1244 | return deps |
michael@0 | 1245 | |
michael@0 | 1246 | class IDLEnum(IDLObjectWithIdentifier): |
michael@0 | 1247 | def __init__(self, location, parentScope, name, values): |
michael@0 | 1248 | assert isinstance(parentScope, IDLScope) |
michael@0 | 1249 | assert isinstance(name, IDLUnresolvedIdentifier) |
michael@0 | 1250 | |
michael@0 | 1251 | if len(values) != len(set(values)): |
michael@0 | 1252 | raise WebIDLError("Enum %s has multiple identical strings" % name.name, |
michael@0 | 1253 | [location]) |
michael@0 | 1254 | |
michael@0 | 1255 | IDLObjectWithIdentifier.__init__(self, location, parentScope, name) |
michael@0 | 1256 | self._values = values |
michael@0 | 1257 | |
michael@0 | 1258 | def values(self): |
michael@0 | 1259 | return self._values |
michael@0 | 1260 | |
michael@0 | 1261 | def finish(self, scope): |
michael@0 | 1262 | pass |
michael@0 | 1263 | |
michael@0 | 1264 | def validate(self): |
michael@0 | 1265 | pass |
michael@0 | 1266 | |
michael@0 | 1267 | def isEnum(self): |
michael@0 | 1268 | return True |
michael@0 | 1269 | |
michael@0 | 1270 | def addExtendedAttributes(self, attrs): |
michael@0 | 1271 | assert len(attrs) == 0 |
michael@0 | 1272 | |
michael@0 | 1273 | def _getDependentObjects(self): |
michael@0 | 1274 | return set() |
michael@0 | 1275 | |
michael@0 | 1276 | class IDLType(IDLObject): |
michael@0 | 1277 | Tags = enum( |
michael@0 | 1278 | # The integer types |
michael@0 | 1279 | 'int8', |
michael@0 | 1280 | 'uint8', |
michael@0 | 1281 | 'int16', |
michael@0 | 1282 | 'uint16', |
michael@0 | 1283 | 'int32', |
michael@0 | 1284 | 'uint32', |
michael@0 | 1285 | 'int64', |
michael@0 | 1286 | 'uint64', |
michael@0 | 1287 | # Additional primitive types |
michael@0 | 1288 | 'bool', |
michael@0 | 1289 | 'unrestricted_float', |
michael@0 | 1290 | 'float', |
michael@0 | 1291 | 'unrestricted_double', |
michael@0 | 1292 | # "double" last primitive type to match IDLBuiltinType |
michael@0 | 1293 | 'double', |
michael@0 | 1294 | # Other types |
michael@0 | 1295 | 'any', |
michael@0 | 1296 | 'domstring', |
michael@0 | 1297 | 'bytestring', |
michael@0 | 1298 | 'object', |
michael@0 | 1299 | 'date', |
michael@0 | 1300 | 'void', |
michael@0 | 1301 | # Funny stuff |
michael@0 | 1302 | 'interface', |
michael@0 | 1303 | 'dictionary', |
michael@0 | 1304 | 'enum', |
michael@0 | 1305 | 'callback', |
michael@0 | 1306 | 'union', |
michael@0 | 1307 | 'sequence', |
michael@0 | 1308 | 'mozmap', |
michael@0 | 1309 | 'array' |
michael@0 | 1310 | ) |
michael@0 | 1311 | |
michael@0 | 1312 | def __init__(self, location, name): |
michael@0 | 1313 | IDLObject.__init__(self, location) |
michael@0 | 1314 | self.name = name |
michael@0 | 1315 | self.builtin = False |
michael@0 | 1316 | |
michael@0 | 1317 | def __eq__(self, other): |
michael@0 | 1318 | return other and self.builtin == other.builtin and self.name == other.name |
michael@0 | 1319 | |
michael@0 | 1320 | def __ne__(self, other): |
michael@0 | 1321 | return not self == other |
michael@0 | 1322 | |
michael@0 | 1323 | def __str__(self): |
michael@0 | 1324 | return str(self.name) |
michael@0 | 1325 | |
michael@0 | 1326 | def isType(self): |
michael@0 | 1327 | return True |
michael@0 | 1328 | |
michael@0 | 1329 | def nullable(self): |
michael@0 | 1330 | return False |
michael@0 | 1331 | |
michael@0 | 1332 | def isPrimitive(self): |
michael@0 | 1333 | return False |
michael@0 | 1334 | |
michael@0 | 1335 | def isBoolean(self): |
michael@0 | 1336 | return False |
michael@0 | 1337 | |
michael@0 | 1338 | def isNumeric(self): |
michael@0 | 1339 | return False |
michael@0 | 1340 | |
michael@0 | 1341 | def isString(self): |
michael@0 | 1342 | return False |
michael@0 | 1343 | |
michael@0 | 1344 | def isByteString(self): |
michael@0 | 1345 | return False |
michael@0 | 1346 | |
michael@0 | 1347 | def isDOMString(self): |
michael@0 | 1348 | return False |
michael@0 | 1349 | |
michael@0 | 1350 | def isVoid(self): |
michael@0 | 1351 | return self.name == "Void" |
michael@0 | 1352 | |
michael@0 | 1353 | def isSequence(self): |
michael@0 | 1354 | return False |
michael@0 | 1355 | |
michael@0 | 1356 | def isMozMap(self): |
michael@0 | 1357 | return False |
michael@0 | 1358 | |
michael@0 | 1359 | def isArray(self): |
michael@0 | 1360 | return False |
michael@0 | 1361 | |
michael@0 | 1362 | def isArrayBuffer(self): |
michael@0 | 1363 | return False |
michael@0 | 1364 | |
michael@0 | 1365 | def isArrayBufferView(self): |
michael@0 | 1366 | return False |
michael@0 | 1367 | |
michael@0 | 1368 | def isTypedArray(self): |
michael@0 | 1369 | return False |
michael@0 | 1370 | |
michael@0 | 1371 | def isCallbackInterface(self): |
michael@0 | 1372 | return False |
michael@0 | 1373 | |
michael@0 | 1374 | def isNonCallbackInterface(self): |
michael@0 | 1375 | return False |
michael@0 | 1376 | |
michael@0 | 1377 | def isGeckoInterface(self): |
michael@0 | 1378 | """ Returns a boolean indicating whether this type is an 'interface' |
michael@0 | 1379 | type that is implemented in Gecko. At the moment, this returns |
michael@0 | 1380 | true for all interface types that are not types from the TypedArray |
michael@0 | 1381 | spec.""" |
michael@0 | 1382 | return self.isInterface() and not self.isSpiderMonkeyInterface() |
michael@0 | 1383 | |
michael@0 | 1384 | def isSpiderMonkeyInterface(self): |
michael@0 | 1385 | """ Returns a boolean indicating whether this type is an 'interface' |
michael@0 | 1386 | type that is implemented in Spidermonkey. At the moment, this |
michael@0 | 1387 | only returns true for the types from the TypedArray spec. """ |
michael@0 | 1388 | return self.isInterface() and (self.isArrayBuffer() or \ |
michael@0 | 1389 | self.isArrayBufferView() or \ |
michael@0 | 1390 | self.isTypedArray()) |
michael@0 | 1391 | |
michael@0 | 1392 | def isDictionary(self): |
michael@0 | 1393 | return False |
michael@0 | 1394 | |
michael@0 | 1395 | def isInterface(self): |
michael@0 | 1396 | return False |
michael@0 | 1397 | |
michael@0 | 1398 | def isAny(self): |
michael@0 | 1399 | return self.tag() == IDLType.Tags.any |
michael@0 | 1400 | |
michael@0 | 1401 | def isDate(self): |
michael@0 | 1402 | return self.tag() == IDLType.Tags.date |
michael@0 | 1403 | |
michael@0 | 1404 | def isObject(self): |
michael@0 | 1405 | return self.tag() == IDLType.Tags.object |
michael@0 | 1406 | |
michael@0 | 1407 | def isPromise(self): |
michael@0 | 1408 | return False |
michael@0 | 1409 | |
michael@0 | 1410 | def isComplete(self): |
michael@0 | 1411 | return True |
michael@0 | 1412 | |
michael@0 | 1413 | def includesRestrictedFloat(self): |
michael@0 | 1414 | return False |
michael@0 | 1415 | |
michael@0 | 1416 | def isFloat(self): |
michael@0 | 1417 | return False |
michael@0 | 1418 | |
michael@0 | 1419 | def isUnrestricted(self): |
michael@0 | 1420 | # Should only call this on float types |
michael@0 | 1421 | assert self.isFloat() |
michael@0 | 1422 | |
michael@0 | 1423 | def isSerializable(self): |
michael@0 | 1424 | return False |
michael@0 | 1425 | |
michael@0 | 1426 | def tag(self): |
michael@0 | 1427 | assert False # Override me! |
michael@0 | 1428 | |
michael@0 | 1429 | def treatNonCallableAsNull(self): |
michael@0 | 1430 | assert self.tag() == IDLType.Tags.callback |
michael@0 | 1431 | return self.nullable() and self.inner._treatNonCallableAsNull |
michael@0 | 1432 | |
michael@0 | 1433 | def treatNonObjectAsNull(self): |
michael@0 | 1434 | assert self.tag() == IDLType.Tags.callback |
michael@0 | 1435 | return self.nullable() and self.inner._treatNonObjectAsNull |
michael@0 | 1436 | |
michael@0 | 1437 | def addExtendedAttributes(self, attrs): |
michael@0 | 1438 | assert len(attrs) == 0 |
michael@0 | 1439 | |
michael@0 | 1440 | def resolveType(self, parentScope): |
michael@0 | 1441 | pass |
michael@0 | 1442 | |
michael@0 | 1443 | def unroll(self): |
michael@0 | 1444 | return self |
michael@0 | 1445 | |
michael@0 | 1446 | def isDistinguishableFrom(self, other): |
michael@0 | 1447 | raise TypeError("Can't tell whether a generic type is or is not " |
michael@0 | 1448 | "distinguishable from other things") |
michael@0 | 1449 | |
michael@0 | 1450 | class IDLUnresolvedType(IDLType): |
michael@0 | 1451 | """ |
michael@0 | 1452 | Unresolved types are interface types |
michael@0 | 1453 | """ |
michael@0 | 1454 | |
michael@0 | 1455 | def __init__(self, location, name): |
michael@0 | 1456 | IDLType.__init__(self, location, name) |
michael@0 | 1457 | |
michael@0 | 1458 | def isComplete(self): |
michael@0 | 1459 | return False |
michael@0 | 1460 | |
michael@0 | 1461 | def complete(self, scope): |
michael@0 | 1462 | obj = None |
michael@0 | 1463 | try: |
michael@0 | 1464 | obj = scope._lookupIdentifier(self.name) |
michael@0 | 1465 | except: |
michael@0 | 1466 | raise WebIDLError("Unresolved type '%s'." % self.name, |
michael@0 | 1467 | [self.location]) |
michael@0 | 1468 | |
michael@0 | 1469 | assert obj |
michael@0 | 1470 | if obj.isType(): |
michael@0 | 1471 | # obj itself might not be complete; deal with that. |
michael@0 | 1472 | assert obj != self |
michael@0 | 1473 | if not obj.isComplete(): |
michael@0 | 1474 | obj = obj.complete(scope) |
michael@0 | 1475 | return obj |
michael@0 | 1476 | |
michael@0 | 1477 | name = self.name.resolve(scope, None) |
michael@0 | 1478 | return IDLWrapperType(self.location, obj) |
michael@0 | 1479 | |
michael@0 | 1480 | def isDistinguishableFrom(self, other): |
michael@0 | 1481 | raise TypeError("Can't tell whether an unresolved type is or is not " |
michael@0 | 1482 | "distinguishable from other things") |
michael@0 | 1483 | |
michael@0 | 1484 | class IDLNullableType(IDLType): |
michael@0 | 1485 | def __init__(self, location, innerType): |
michael@0 | 1486 | assert not innerType.isVoid() |
michael@0 | 1487 | assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any] |
michael@0 | 1488 | |
michael@0 | 1489 | IDLType.__init__(self, location, innerType.name) |
michael@0 | 1490 | self.inner = innerType |
michael@0 | 1491 | self.builtin = False |
michael@0 | 1492 | |
michael@0 | 1493 | def __eq__(self, other): |
michael@0 | 1494 | return isinstance(other, IDLNullableType) and self.inner == other.inner |
michael@0 | 1495 | |
michael@0 | 1496 | def __str__(self): |
michael@0 | 1497 | return self.inner.__str__() + "OrNull" |
michael@0 | 1498 | |
michael@0 | 1499 | def nullable(self): |
michael@0 | 1500 | return True |
michael@0 | 1501 | |
michael@0 | 1502 | def isCallback(self): |
michael@0 | 1503 | return self.inner.isCallback() |
michael@0 | 1504 | |
michael@0 | 1505 | def isPrimitive(self): |
michael@0 | 1506 | return self.inner.isPrimitive() |
michael@0 | 1507 | |
michael@0 | 1508 | def isBoolean(self): |
michael@0 | 1509 | return self.inner.isBoolean() |
michael@0 | 1510 | |
michael@0 | 1511 | def isNumeric(self): |
michael@0 | 1512 | return self.inner.isNumeric() |
michael@0 | 1513 | |
michael@0 | 1514 | def isString(self): |
michael@0 | 1515 | return self.inner.isString() |
michael@0 | 1516 | |
michael@0 | 1517 | def isByteString(self): |
michael@0 | 1518 | return self.inner.isByteString() |
michael@0 | 1519 | |
michael@0 | 1520 | def isDOMString(self): |
michael@0 | 1521 | return self.inner.isDOMString() |
michael@0 | 1522 | |
michael@0 | 1523 | def isFloat(self): |
michael@0 | 1524 | return self.inner.isFloat() |
michael@0 | 1525 | |
michael@0 | 1526 | def isUnrestricted(self): |
michael@0 | 1527 | return self.inner.isUnrestricted() |
michael@0 | 1528 | |
michael@0 | 1529 | def includesRestrictedFloat(self): |
michael@0 | 1530 | return self.inner.includesRestrictedFloat() |
michael@0 | 1531 | |
michael@0 | 1532 | def isInteger(self): |
michael@0 | 1533 | return self.inner.isInteger() |
michael@0 | 1534 | |
michael@0 | 1535 | def isVoid(self): |
michael@0 | 1536 | return False |
michael@0 | 1537 | |
michael@0 | 1538 | def isSequence(self): |
michael@0 | 1539 | return self.inner.isSequence() |
michael@0 | 1540 | |
michael@0 | 1541 | def isMozMap(self): |
michael@0 | 1542 | return self.inner.isMozMap() |
michael@0 | 1543 | |
michael@0 | 1544 | def isArray(self): |
michael@0 | 1545 | return self.inner.isArray() |
michael@0 | 1546 | |
michael@0 | 1547 | def isArrayBuffer(self): |
michael@0 | 1548 | return self.inner.isArrayBuffer() |
michael@0 | 1549 | |
michael@0 | 1550 | def isArrayBufferView(self): |
michael@0 | 1551 | return self.inner.isArrayBufferView() |
michael@0 | 1552 | |
michael@0 | 1553 | def isTypedArray(self): |
michael@0 | 1554 | return self.inner.isTypedArray() |
michael@0 | 1555 | |
michael@0 | 1556 | def isDictionary(self): |
michael@0 | 1557 | return self.inner.isDictionary() |
michael@0 | 1558 | |
michael@0 | 1559 | def isInterface(self): |
michael@0 | 1560 | return self.inner.isInterface() |
michael@0 | 1561 | |
michael@0 | 1562 | def isCallbackInterface(self): |
michael@0 | 1563 | return self.inner.isCallbackInterface() |
michael@0 | 1564 | |
michael@0 | 1565 | def isNonCallbackInterface(self): |
michael@0 | 1566 | return self.inner.isNonCallbackInterface() |
michael@0 | 1567 | |
michael@0 | 1568 | def isEnum(self): |
michael@0 | 1569 | return self.inner.isEnum() |
michael@0 | 1570 | |
michael@0 | 1571 | def isUnion(self): |
michael@0 | 1572 | return self.inner.isUnion() |
michael@0 | 1573 | |
michael@0 | 1574 | def isSerializable(self): |
michael@0 | 1575 | return self.inner.isSerializable() |
michael@0 | 1576 | |
michael@0 | 1577 | def tag(self): |
michael@0 | 1578 | return self.inner.tag() |
michael@0 | 1579 | |
michael@0 | 1580 | def resolveType(self, parentScope): |
michael@0 | 1581 | assert isinstance(parentScope, IDLScope) |
michael@0 | 1582 | self.inner.resolveType(parentScope) |
michael@0 | 1583 | |
michael@0 | 1584 | def isComplete(self): |
michael@0 | 1585 | return self.inner.isComplete() |
michael@0 | 1586 | |
michael@0 | 1587 | def complete(self, scope): |
michael@0 | 1588 | self.inner = self.inner.complete(scope) |
michael@0 | 1589 | if self.inner.nullable(): |
michael@0 | 1590 | raise WebIDLError("The inner type of a nullable type must not be " |
michael@0 | 1591 | "a nullable type", |
michael@0 | 1592 | [self.location, self.inner.location]) |
michael@0 | 1593 | if self.inner.isUnion(): |
michael@0 | 1594 | if self.inner.hasNullableType: |
michael@0 | 1595 | raise WebIDLError("The inner type of a nullable type must not " |
michael@0 | 1596 | "be a union type that itself has a nullable " |
michael@0 | 1597 | "type as a member type", [self.location]) |
michael@0 | 1598 | |
michael@0 | 1599 | self.name = self.inner.name |
michael@0 | 1600 | return self |
michael@0 | 1601 | |
michael@0 | 1602 | def unroll(self): |
michael@0 | 1603 | return self.inner.unroll() |
michael@0 | 1604 | |
michael@0 | 1605 | def isDistinguishableFrom(self, other): |
michael@0 | 1606 | if (other.nullable() or (other.isUnion() and other.hasNullableType) or |
michael@0 | 1607 | other.isDictionary()): |
michael@0 | 1608 | # Can't tell which type null should become |
michael@0 | 1609 | return False |
michael@0 | 1610 | return self.inner.isDistinguishableFrom(other) |
michael@0 | 1611 | |
michael@0 | 1612 | def _getDependentObjects(self): |
michael@0 | 1613 | return self.inner._getDependentObjects() |
michael@0 | 1614 | |
michael@0 | 1615 | class IDLSequenceType(IDLType): |
michael@0 | 1616 | def __init__(self, location, parameterType): |
michael@0 | 1617 | assert not parameterType.isVoid() |
michael@0 | 1618 | |
michael@0 | 1619 | IDLType.__init__(self, location, parameterType.name) |
michael@0 | 1620 | self.inner = parameterType |
michael@0 | 1621 | self.builtin = False |
michael@0 | 1622 | |
michael@0 | 1623 | def __eq__(self, other): |
michael@0 | 1624 | return isinstance(other, IDLSequenceType) and self.inner == other.inner |
michael@0 | 1625 | |
michael@0 | 1626 | def __str__(self): |
michael@0 | 1627 | return self.inner.__str__() + "Sequence" |
michael@0 | 1628 | |
michael@0 | 1629 | def nullable(self): |
michael@0 | 1630 | return False |
michael@0 | 1631 | |
michael@0 | 1632 | def isPrimitive(self): |
michael@0 | 1633 | return False; |
michael@0 | 1634 | |
michael@0 | 1635 | def isString(self): |
michael@0 | 1636 | return False; |
michael@0 | 1637 | |
michael@0 | 1638 | def isByteString(self): |
michael@0 | 1639 | return False |
michael@0 | 1640 | |
michael@0 | 1641 | def isDOMString(self): |
michael@0 | 1642 | return False |
michael@0 | 1643 | |
michael@0 | 1644 | def isVoid(self): |
michael@0 | 1645 | return False |
michael@0 | 1646 | |
michael@0 | 1647 | def isSequence(self): |
michael@0 | 1648 | return True |
michael@0 | 1649 | |
michael@0 | 1650 | def isArray(self): |
michael@0 | 1651 | return False |
michael@0 | 1652 | |
michael@0 | 1653 | def isDictionary(self): |
michael@0 | 1654 | return False |
michael@0 | 1655 | |
michael@0 | 1656 | def isInterface(self): |
michael@0 | 1657 | return False |
michael@0 | 1658 | |
michael@0 | 1659 | def isEnum(self): |
michael@0 | 1660 | return False |
michael@0 | 1661 | |
michael@0 | 1662 | def isSerializable(self): |
michael@0 | 1663 | return self.inner.isSerializable() |
michael@0 | 1664 | |
michael@0 | 1665 | def includesRestrictedFloat(self): |
michael@0 | 1666 | return self.inner.includesRestrictedFloat() |
michael@0 | 1667 | |
michael@0 | 1668 | def tag(self): |
michael@0 | 1669 | return IDLType.Tags.sequence |
michael@0 | 1670 | |
michael@0 | 1671 | def resolveType(self, parentScope): |
michael@0 | 1672 | assert isinstance(parentScope, IDLScope) |
michael@0 | 1673 | self.inner.resolveType(parentScope) |
michael@0 | 1674 | |
michael@0 | 1675 | def isComplete(self): |
michael@0 | 1676 | return self.inner.isComplete() |
michael@0 | 1677 | |
michael@0 | 1678 | def complete(self, scope): |
michael@0 | 1679 | self.inner = self.inner.complete(scope) |
michael@0 | 1680 | self.name = self.inner.name |
michael@0 | 1681 | return self |
michael@0 | 1682 | |
michael@0 | 1683 | def unroll(self): |
michael@0 | 1684 | return self.inner.unroll() |
michael@0 | 1685 | |
michael@0 | 1686 | def isDistinguishableFrom(self, other): |
michael@0 | 1687 | if other.isUnion(): |
michael@0 | 1688 | # Just forward to the union; it'll deal |
michael@0 | 1689 | return other.isDistinguishableFrom(self) |
michael@0 | 1690 | return (other.isPrimitive() or other.isString() or other.isEnum() or |
michael@0 | 1691 | other.isDate() or other.isNonCallbackInterface()) |
michael@0 | 1692 | |
michael@0 | 1693 | def _getDependentObjects(self): |
michael@0 | 1694 | return self.inner._getDependentObjects() |
michael@0 | 1695 | |
michael@0 | 1696 | class IDLMozMapType(IDLType): |
michael@0 | 1697 | # XXXbz This is pretty similar to IDLSequenceType in various ways. |
michael@0 | 1698 | # And maybe to IDLNullableType. Should we have a superclass for |
michael@0 | 1699 | # "type containing this other type"? Bug 1015318. |
michael@0 | 1700 | def __init__(self, location, parameterType): |
michael@0 | 1701 | assert not parameterType.isVoid() |
michael@0 | 1702 | |
michael@0 | 1703 | IDLType.__init__(self, location, parameterType.name) |
michael@0 | 1704 | self.inner = parameterType |
michael@0 | 1705 | self.builtin = False |
michael@0 | 1706 | |
michael@0 | 1707 | def __eq__(self, other): |
michael@0 | 1708 | return isinstance(other, IDLMozMapType) and self.inner == other.inner |
michael@0 | 1709 | |
michael@0 | 1710 | def __str__(self): |
michael@0 | 1711 | return self.inner.__str__() + "MozMap" |
michael@0 | 1712 | |
michael@0 | 1713 | def isMozMap(self): |
michael@0 | 1714 | return True |
michael@0 | 1715 | |
michael@0 | 1716 | def includesRestrictedFloat(self): |
michael@0 | 1717 | return self.inner.includesRestrictedFloat() |
michael@0 | 1718 | |
michael@0 | 1719 | def tag(self): |
michael@0 | 1720 | return IDLType.Tags.mozmap |
michael@0 | 1721 | |
michael@0 | 1722 | def resolveType(self, parentScope): |
michael@0 | 1723 | assert isinstance(parentScope, IDLScope) |
michael@0 | 1724 | self.inner.resolveType(parentScope) |
michael@0 | 1725 | |
michael@0 | 1726 | def isComplete(self): |
michael@0 | 1727 | return self.inner.isComplete() |
michael@0 | 1728 | |
michael@0 | 1729 | def complete(self, scope): |
michael@0 | 1730 | self.inner = self.inner.complete(scope) |
michael@0 | 1731 | self.name = self.inner.name |
michael@0 | 1732 | return self |
michael@0 | 1733 | |
michael@0 | 1734 | def unroll(self): |
michael@0 | 1735 | # We do not unroll our inner. Just stop at ourselves. That |
michael@0 | 1736 | # lets us add headers for both ourselves and our inner as |
michael@0 | 1737 | # needed. |
michael@0 | 1738 | return self |
michael@0 | 1739 | |
michael@0 | 1740 | def isDistinguishableFrom(self, other): |
michael@0 | 1741 | if other.isUnion(): |
michael@0 | 1742 | # Just forward to the union; it'll deal |
michael@0 | 1743 | return other.isDistinguishableFrom(self) |
michael@0 | 1744 | return (other.isPrimitive() or other.isString() or other.isEnum() or |
michael@0 | 1745 | other.isDate() or other.isNonCallbackInterface()) |
michael@0 | 1746 | |
michael@0 | 1747 | def _getDependentObjects(self): |
michael@0 | 1748 | return self.inner._getDependentObjects() |
michael@0 | 1749 | |
michael@0 | 1750 | class IDLUnionType(IDLType): |
michael@0 | 1751 | def __init__(self, location, memberTypes): |
michael@0 | 1752 | IDLType.__init__(self, location, "") |
michael@0 | 1753 | self.memberTypes = memberTypes |
michael@0 | 1754 | self.hasNullableType = False |
michael@0 | 1755 | self.hasDictionaryType = False |
michael@0 | 1756 | self.flatMemberTypes = None |
michael@0 | 1757 | self.builtin = False |
michael@0 | 1758 | |
michael@0 | 1759 | def __eq__(self, other): |
michael@0 | 1760 | return isinstance(other, IDLUnionType) and self.memberTypes == other.memberTypes |
michael@0 | 1761 | |
michael@0 | 1762 | def isVoid(self): |
michael@0 | 1763 | return False |
michael@0 | 1764 | |
michael@0 | 1765 | def isUnion(self): |
michael@0 | 1766 | return True |
michael@0 | 1767 | |
michael@0 | 1768 | def isSerializable(self): |
michael@0 | 1769 | return all(m.isSerializable() for m in self.memberTypes) |
michael@0 | 1770 | |
michael@0 | 1771 | def includesRestrictedFloat(self): |
michael@0 | 1772 | return any(t.includesRestrictedFloat() for t in self.memberTypes) |
michael@0 | 1773 | |
michael@0 | 1774 | def tag(self): |
michael@0 | 1775 | return IDLType.Tags.union |
michael@0 | 1776 | |
michael@0 | 1777 | def resolveType(self, parentScope): |
michael@0 | 1778 | assert isinstance(parentScope, IDLScope) |
michael@0 | 1779 | for t in self.memberTypes: |
michael@0 | 1780 | t.resolveType(parentScope) |
michael@0 | 1781 | |
michael@0 | 1782 | def isComplete(self): |
michael@0 | 1783 | return self.flatMemberTypes is not None |
michael@0 | 1784 | |
michael@0 | 1785 | def complete(self, scope): |
michael@0 | 1786 | def typeName(type): |
michael@0 | 1787 | if isinstance(type, IDLNullableType): |
michael@0 | 1788 | return typeName(type.inner) + "OrNull" |
michael@0 | 1789 | if isinstance(type, IDLWrapperType): |
michael@0 | 1790 | return typeName(type._identifier.object()) |
michael@0 | 1791 | if isinstance(type, IDLObjectWithIdentifier): |
michael@0 | 1792 | return typeName(type.identifier) |
michael@0 | 1793 | if (isinstance(type, IDLType) and |
michael@0 | 1794 | (type.isArray() or type.isSequence() or type.isMozMap)): |
michael@0 | 1795 | return str(type) |
michael@0 | 1796 | return type.name |
michael@0 | 1797 | |
michael@0 | 1798 | for (i, type) in enumerate(self.memberTypes): |
michael@0 | 1799 | if not type.isComplete(): |
michael@0 | 1800 | self.memberTypes[i] = type.complete(scope) |
michael@0 | 1801 | |
michael@0 | 1802 | self.name = "Or".join(typeName(type) for type in self.memberTypes) |
michael@0 | 1803 | self.flatMemberTypes = list(self.memberTypes) |
michael@0 | 1804 | i = 0 |
michael@0 | 1805 | while i < len(self.flatMemberTypes): |
michael@0 | 1806 | if self.flatMemberTypes[i].nullable(): |
michael@0 | 1807 | if self.hasNullableType: |
michael@0 | 1808 | raise WebIDLError("Can't have more than one nullable types in a union", |
michael@0 | 1809 | [nullableType.location, self.flatMemberTypes[i].location]) |
michael@0 | 1810 | if self.hasDictionaryType: |
michael@0 | 1811 | raise WebIDLError("Can't have a nullable type and a " |
michael@0 | 1812 | "dictionary type in a union", |
michael@0 | 1813 | [dictionaryType.location, |
michael@0 | 1814 | self.flatMemberTypes[i].location]) |
michael@0 | 1815 | self.hasNullableType = True |
michael@0 | 1816 | nullableType = self.flatMemberTypes[i] |
michael@0 | 1817 | self.flatMemberTypes[i] = self.flatMemberTypes[i].inner |
michael@0 | 1818 | continue |
michael@0 | 1819 | if self.flatMemberTypes[i].isDictionary(): |
michael@0 | 1820 | if self.hasNullableType: |
michael@0 | 1821 | raise WebIDLError("Can't have a nullable type and a " |
michael@0 | 1822 | "dictionary type in a union", |
michael@0 | 1823 | [nullableType.location, |
michael@0 | 1824 | self.flatMemberTypes[i].location]) |
michael@0 | 1825 | self.hasDictionaryType = True |
michael@0 | 1826 | dictionaryType = self.flatMemberTypes[i] |
michael@0 | 1827 | elif self.flatMemberTypes[i].isUnion(): |
michael@0 | 1828 | self.flatMemberTypes[i:i + 1] = self.flatMemberTypes[i].memberTypes |
michael@0 | 1829 | continue |
michael@0 | 1830 | i += 1 |
michael@0 | 1831 | |
michael@0 | 1832 | for (i, t) in enumerate(self.flatMemberTypes[:-1]): |
michael@0 | 1833 | for u in self.flatMemberTypes[i + 1:]: |
michael@0 | 1834 | if not t.isDistinguishableFrom(u): |
michael@0 | 1835 | raise WebIDLError("Flat member types of a union should be " |
michael@0 | 1836 | "distinguishable, " + str(t) + " is not " |
michael@0 | 1837 | "distinguishable from " + str(u), |
michael@0 | 1838 | [self.location, t.location, u.location]) |
michael@0 | 1839 | |
michael@0 | 1840 | return self |
michael@0 | 1841 | |
michael@0 | 1842 | def isDistinguishableFrom(self, other): |
michael@0 | 1843 | if self.hasNullableType and other.nullable(): |
michael@0 | 1844 | # Can't tell which type null should become |
michael@0 | 1845 | return False |
michael@0 | 1846 | if other.isUnion(): |
michael@0 | 1847 | otherTypes = other.unroll().memberTypes |
michael@0 | 1848 | else: |
michael@0 | 1849 | otherTypes = [other] |
michael@0 | 1850 | # For every type in otherTypes, check that it's distinguishable from |
michael@0 | 1851 | # every type in our types |
michael@0 | 1852 | for u in otherTypes: |
michael@0 | 1853 | if any(not t.isDistinguishableFrom(u) for t in self.memberTypes): |
michael@0 | 1854 | return False |
michael@0 | 1855 | return True |
michael@0 | 1856 | |
michael@0 | 1857 | def _getDependentObjects(self): |
michael@0 | 1858 | return set(self.memberTypes) |
michael@0 | 1859 | |
michael@0 | 1860 | class IDLArrayType(IDLType): |
michael@0 | 1861 | def __init__(self, location, parameterType): |
michael@0 | 1862 | assert not parameterType.isVoid() |
michael@0 | 1863 | if parameterType.isSequence(): |
michael@0 | 1864 | raise WebIDLError("Array type cannot parameterize over a sequence type", |
michael@0 | 1865 | [location]) |
michael@0 | 1866 | if parameterType.isMozMap(): |
michael@0 | 1867 | raise WebIDLError("Array type cannot parameterize over a MozMap type", |
michael@0 | 1868 | [location]) |
michael@0 | 1869 | if parameterType.isDictionary(): |
michael@0 | 1870 | raise WebIDLError("Array type cannot parameterize over a dictionary type", |
michael@0 | 1871 | [location]) |
michael@0 | 1872 | |
michael@0 | 1873 | IDLType.__init__(self, location, parameterType.name) |
michael@0 | 1874 | self.inner = parameterType |
michael@0 | 1875 | self.builtin = False |
michael@0 | 1876 | |
michael@0 | 1877 | def __eq__(self, other): |
michael@0 | 1878 | return isinstance(other, IDLArrayType) and self.inner == other.inner |
michael@0 | 1879 | |
michael@0 | 1880 | def __str__(self): |
michael@0 | 1881 | return self.inner.__str__() + "Array" |
michael@0 | 1882 | |
michael@0 | 1883 | def nullable(self): |
michael@0 | 1884 | return False |
michael@0 | 1885 | |
michael@0 | 1886 | def isPrimitive(self): |
michael@0 | 1887 | return False |
michael@0 | 1888 | |
michael@0 | 1889 | def isString(self): |
michael@0 | 1890 | return False |
michael@0 | 1891 | |
michael@0 | 1892 | def isByteString(self): |
michael@0 | 1893 | return False |
michael@0 | 1894 | |
michael@0 | 1895 | def isDOMString(self): |
michael@0 | 1896 | return False |
michael@0 | 1897 | |
michael@0 | 1898 | def isVoid(self): |
michael@0 | 1899 | return False |
michael@0 | 1900 | |
michael@0 | 1901 | def isSequence(self): |
michael@0 | 1902 | assert not self.inner.isSequence() |
michael@0 | 1903 | return False |
michael@0 | 1904 | |
michael@0 | 1905 | def isArray(self): |
michael@0 | 1906 | return True |
michael@0 | 1907 | |
michael@0 | 1908 | def isDictionary(self): |
michael@0 | 1909 | assert not self.inner.isDictionary() |
michael@0 | 1910 | return False |
michael@0 | 1911 | |
michael@0 | 1912 | def isInterface(self): |
michael@0 | 1913 | return False |
michael@0 | 1914 | |
michael@0 | 1915 | def isEnum(self): |
michael@0 | 1916 | return False |
michael@0 | 1917 | |
michael@0 | 1918 | def tag(self): |
michael@0 | 1919 | return IDLType.Tags.array |
michael@0 | 1920 | |
michael@0 | 1921 | def resolveType(self, parentScope): |
michael@0 | 1922 | assert isinstance(parentScope, IDLScope) |
michael@0 | 1923 | self.inner.resolveType(parentScope) |
michael@0 | 1924 | |
michael@0 | 1925 | def isComplete(self): |
michael@0 | 1926 | return self.inner.isComplete() |
michael@0 | 1927 | |
michael@0 | 1928 | def complete(self, scope): |
michael@0 | 1929 | self.inner = self.inner.complete(scope) |
michael@0 | 1930 | self.name = self.inner.name |
michael@0 | 1931 | |
michael@0 | 1932 | if self.inner.isDictionary(): |
michael@0 | 1933 | raise WebIDLError("Array type must not contain " |
michael@0 | 1934 | "dictionary as element type.", |
michael@0 | 1935 | [self.inner.location]) |
michael@0 | 1936 | |
michael@0 | 1937 | assert not self.inner.isSequence() |
michael@0 | 1938 | |
michael@0 | 1939 | return self |
michael@0 | 1940 | |
michael@0 | 1941 | def unroll(self): |
michael@0 | 1942 | return self.inner.unroll() |
michael@0 | 1943 | |
michael@0 | 1944 | def isDistinguishableFrom(self, other): |
michael@0 | 1945 | if other.isUnion(): |
michael@0 | 1946 | # Just forward to the union; it'll deal |
michael@0 | 1947 | return other.isDistinguishableFrom(self) |
michael@0 | 1948 | return (other.isPrimitive() or other.isString() or other.isEnum() or |
michael@0 | 1949 | other.isDate() or other.isNonCallbackInterface()) |
michael@0 | 1950 | |
michael@0 | 1951 | def _getDependentObjects(self): |
michael@0 | 1952 | return self.inner._getDependentObjects() |
michael@0 | 1953 | |
michael@0 | 1954 | class IDLTypedefType(IDLType, IDLObjectWithIdentifier): |
michael@0 | 1955 | def __init__(self, location, innerType, name): |
michael@0 | 1956 | IDLType.__init__(self, location, innerType.name) |
michael@0 | 1957 | |
michael@0 | 1958 | identifier = IDLUnresolvedIdentifier(location, name) |
michael@0 | 1959 | |
michael@0 | 1960 | IDLObjectWithIdentifier.__init__(self, location, None, identifier) |
michael@0 | 1961 | |
michael@0 | 1962 | self.inner = innerType |
michael@0 | 1963 | self.name = name |
michael@0 | 1964 | self.builtin = False |
michael@0 | 1965 | |
michael@0 | 1966 | def __eq__(self, other): |
michael@0 | 1967 | return isinstance(other, IDLTypedefType) and self.inner == other.inner |
michael@0 | 1968 | |
michael@0 | 1969 | def __str__(self): |
michael@0 | 1970 | return self.identifier.name |
michael@0 | 1971 | |
michael@0 | 1972 | def nullable(self): |
michael@0 | 1973 | return self.inner.nullable() |
michael@0 | 1974 | |
michael@0 | 1975 | def isPrimitive(self): |
michael@0 | 1976 | return self.inner.isPrimitive() |
michael@0 | 1977 | |
michael@0 | 1978 | def isBoolean(self): |
michael@0 | 1979 | return self.inner.isBoolean() |
michael@0 | 1980 | |
michael@0 | 1981 | def isNumeric(self): |
michael@0 | 1982 | return self.inner.isNumeric() |
michael@0 | 1983 | |
michael@0 | 1984 | def isString(self): |
michael@0 | 1985 | return self.inner.isString() |
michael@0 | 1986 | |
michael@0 | 1987 | def isByteString(self): |
michael@0 | 1988 | return self.inner.isByteString() |
michael@0 | 1989 | |
michael@0 | 1990 | def isDOMString(self): |
michael@0 | 1991 | return self.inner.isDOMString() |
michael@0 | 1992 | |
michael@0 | 1993 | def isVoid(self): |
michael@0 | 1994 | return self.inner.isVoid() |
michael@0 | 1995 | |
michael@0 | 1996 | def isSequence(self): |
michael@0 | 1997 | return self.inner.isSequence() |
michael@0 | 1998 | |
michael@0 | 1999 | def isMozMap(self): |
michael@0 | 2000 | return self.inner.isMozMap() |
michael@0 | 2001 | |
michael@0 | 2002 | def isArray(self): |
michael@0 | 2003 | return self.inner.isArray() |
michael@0 | 2004 | |
michael@0 | 2005 | def isDictionary(self): |
michael@0 | 2006 | return self.inner.isDictionary() |
michael@0 | 2007 | |
michael@0 | 2008 | def isArrayBuffer(self): |
michael@0 | 2009 | return self.inner.isArrayBuffer() |
michael@0 | 2010 | |
michael@0 | 2011 | def isArrayBufferView(self): |
michael@0 | 2012 | return self.inner.isArrayBufferView() |
michael@0 | 2013 | |
michael@0 | 2014 | def isTypedArray(self): |
michael@0 | 2015 | return self.inner.isTypedArray() |
michael@0 | 2016 | |
michael@0 | 2017 | def isInterface(self): |
michael@0 | 2018 | return self.inner.isInterface() |
michael@0 | 2019 | |
michael@0 | 2020 | def isCallbackInterface(self): |
michael@0 | 2021 | return self.inner.isCallbackInterface() |
michael@0 | 2022 | |
michael@0 | 2023 | def isNonCallbackInterface(self): |
michael@0 | 2024 | return self.inner.isNonCallbackInterface() |
michael@0 | 2025 | |
michael@0 | 2026 | def isComplete(self): |
michael@0 | 2027 | return False |
michael@0 | 2028 | |
michael@0 | 2029 | def complete(self, parentScope): |
michael@0 | 2030 | if not self.inner.isComplete(): |
michael@0 | 2031 | self.inner = self.inner.complete(parentScope) |
michael@0 | 2032 | assert self.inner.isComplete() |
michael@0 | 2033 | return self.inner |
michael@0 | 2034 | |
michael@0 | 2035 | def finish(self, parentScope): |
michael@0 | 2036 | # Maybe the IDLObjectWithIdentifier for the typedef should be |
michael@0 | 2037 | # a separate thing from the type? If that happens, we can |
michael@0 | 2038 | # remove some hackery around avoiding isInterface() in |
michael@0 | 2039 | # Configuration.py. |
michael@0 | 2040 | self.complete(parentScope) |
michael@0 | 2041 | |
michael@0 | 2042 | def validate(self): |
michael@0 | 2043 | pass |
michael@0 | 2044 | |
michael@0 | 2045 | # Do we need a resolveType impl? I don't think it's particularly useful.... |
michael@0 | 2046 | |
michael@0 | 2047 | def tag(self): |
michael@0 | 2048 | return self.inner.tag() |
michael@0 | 2049 | |
michael@0 | 2050 | def unroll(self): |
michael@0 | 2051 | return self.inner.unroll() |
michael@0 | 2052 | |
michael@0 | 2053 | def isDistinguishableFrom(self, other): |
michael@0 | 2054 | return self.inner.isDistinguishableFrom(other) |
michael@0 | 2055 | |
michael@0 | 2056 | def _getDependentObjects(self): |
michael@0 | 2057 | return self.inner._getDependentObjects() |
michael@0 | 2058 | |
michael@0 | 2059 | class IDLWrapperType(IDLType): |
michael@0 | 2060 | def __init__(self, location, inner): |
michael@0 | 2061 | IDLType.__init__(self, location, inner.identifier.name) |
michael@0 | 2062 | self.inner = inner |
michael@0 | 2063 | self._identifier = inner.identifier |
michael@0 | 2064 | self.builtin = False |
michael@0 | 2065 | |
michael@0 | 2066 | def __eq__(self, other): |
michael@0 | 2067 | return isinstance(other, IDLWrapperType) and \ |
michael@0 | 2068 | self._identifier == other._identifier and \ |
michael@0 | 2069 | self.builtin == other.builtin |
michael@0 | 2070 | |
michael@0 | 2071 | def __str__(self): |
michael@0 | 2072 | return str(self.name) + " (Wrapper)" |
michael@0 | 2073 | |
michael@0 | 2074 | def nullable(self): |
michael@0 | 2075 | return False |
michael@0 | 2076 | |
michael@0 | 2077 | def isPrimitive(self): |
michael@0 | 2078 | return False |
michael@0 | 2079 | |
michael@0 | 2080 | def isString(self): |
michael@0 | 2081 | return False |
michael@0 | 2082 | |
michael@0 | 2083 | def isByteString(self): |
michael@0 | 2084 | return False |
michael@0 | 2085 | |
michael@0 | 2086 | def isDOMString(self): |
michael@0 | 2087 | return False |
michael@0 | 2088 | |
michael@0 | 2089 | def isVoid(self): |
michael@0 | 2090 | return False |
michael@0 | 2091 | |
michael@0 | 2092 | def isSequence(self): |
michael@0 | 2093 | return False |
michael@0 | 2094 | |
michael@0 | 2095 | def isArray(self): |
michael@0 | 2096 | return False |
michael@0 | 2097 | |
michael@0 | 2098 | def isDictionary(self): |
michael@0 | 2099 | return isinstance(self.inner, IDLDictionary) |
michael@0 | 2100 | |
michael@0 | 2101 | def isInterface(self): |
michael@0 | 2102 | return isinstance(self.inner, IDLInterface) or \ |
michael@0 | 2103 | isinstance(self.inner, IDLExternalInterface) |
michael@0 | 2104 | |
michael@0 | 2105 | def isCallbackInterface(self): |
michael@0 | 2106 | return self.isInterface() and self.inner.isCallback() |
michael@0 | 2107 | |
michael@0 | 2108 | def isNonCallbackInterface(self): |
michael@0 | 2109 | return self.isInterface() and not self.inner.isCallback() |
michael@0 | 2110 | |
michael@0 | 2111 | def isEnum(self): |
michael@0 | 2112 | return isinstance(self.inner, IDLEnum) |
michael@0 | 2113 | |
michael@0 | 2114 | def isPromise(self): |
michael@0 | 2115 | return isinstance(self.inner, IDLInterface) and \ |
michael@0 | 2116 | self.inner.identifier.name == "Promise" |
michael@0 | 2117 | |
michael@0 | 2118 | def isSerializable(self): |
michael@0 | 2119 | if self.isInterface(): |
michael@0 | 2120 | if self.inner.isExternal(): |
michael@0 | 2121 | return False |
michael@0 | 2122 | return any(m.isMethod() and m.isJsonifier() for m in self.inner.members) |
michael@0 | 2123 | elif self.isEnum(): |
michael@0 | 2124 | return True |
michael@0 | 2125 | elif self.isDictionary(): |
michael@0 | 2126 | return all(m.type.isSerializable() for m in self.inner.members) |
michael@0 | 2127 | else: |
michael@0 | 2128 | raise WebIDLError("IDLWrapperType wraps type %s that we don't know if " |
michael@0 | 2129 | "is serializable" % type(self.inner), [self.location]) |
michael@0 | 2130 | |
michael@0 | 2131 | def resolveType(self, parentScope): |
michael@0 | 2132 | assert isinstance(parentScope, IDLScope) |
michael@0 | 2133 | self.inner.resolve(parentScope) |
michael@0 | 2134 | |
michael@0 | 2135 | def isComplete(self): |
michael@0 | 2136 | return True |
michael@0 | 2137 | |
michael@0 | 2138 | def tag(self): |
michael@0 | 2139 | if self.isInterface(): |
michael@0 | 2140 | return IDLType.Tags.interface |
michael@0 | 2141 | elif self.isEnum(): |
michael@0 | 2142 | return IDLType.Tags.enum |
michael@0 | 2143 | elif self.isDictionary(): |
michael@0 | 2144 | return IDLType.Tags.dictionary |
michael@0 | 2145 | else: |
michael@0 | 2146 | assert False |
michael@0 | 2147 | |
michael@0 | 2148 | def isDistinguishableFrom(self, other): |
michael@0 | 2149 | if other.isUnion(): |
michael@0 | 2150 | # Just forward to the union; it'll deal |
michael@0 | 2151 | return other.isDistinguishableFrom(self) |
michael@0 | 2152 | assert self.isInterface() or self.isEnum() or self.isDictionary() |
michael@0 | 2153 | if self.isEnum(): |
michael@0 | 2154 | return (other.isPrimitive() or other.isInterface() or other.isObject() or |
michael@0 | 2155 | other.isCallback() or other.isDictionary() or |
michael@0 | 2156 | other.isSequence() or other.isMozMap() or other.isArray() or |
michael@0 | 2157 | other.isDate()) |
michael@0 | 2158 | if self.isDictionary() and other.nullable(): |
michael@0 | 2159 | return False |
michael@0 | 2160 | if other.isPrimitive() or other.isString() or other.isEnum() or other.isDate(): |
michael@0 | 2161 | return True |
michael@0 | 2162 | if self.isDictionary(): |
michael@0 | 2163 | return other.isNonCallbackInterface() |
michael@0 | 2164 | |
michael@0 | 2165 | assert self.isInterface() |
michael@0 | 2166 | if other.isInterface(): |
michael@0 | 2167 | if other.isSpiderMonkeyInterface(): |
michael@0 | 2168 | # Just let |other| handle things |
michael@0 | 2169 | return other.isDistinguishableFrom(self) |
michael@0 | 2170 | assert self.isGeckoInterface() and other.isGeckoInterface() |
michael@0 | 2171 | if self.inner.isExternal() or other.unroll().inner.isExternal(): |
michael@0 | 2172 | return self != other |
michael@0 | 2173 | return (len(self.inner.interfacesBasedOnSelf & |
michael@0 | 2174 | other.unroll().inner.interfacesBasedOnSelf) == 0 and |
michael@0 | 2175 | (self.isNonCallbackInterface() or |
michael@0 | 2176 | other.isNonCallbackInterface())) |
michael@0 | 2177 | if (other.isDictionary() or other.isCallback() or |
michael@0 | 2178 | other.isSequence() or other.isMozMap() or other.isArray()): |
michael@0 | 2179 | return self.isNonCallbackInterface() |
michael@0 | 2180 | |
michael@0 | 2181 | # Not much else |other| can be |
michael@0 | 2182 | assert other.isObject() |
michael@0 | 2183 | return False |
michael@0 | 2184 | |
michael@0 | 2185 | def _getDependentObjects(self): |
michael@0 | 2186 | # NB: The codegen for an interface type depends on |
michael@0 | 2187 | # a) That the identifier is in fact an interface (as opposed to |
michael@0 | 2188 | # a dictionary or something else). |
michael@0 | 2189 | # b) The native type of the interface. |
michael@0 | 2190 | # If we depend on the interface object we will also depend on |
michael@0 | 2191 | # anything the interface depends on which is undesirable. We |
michael@0 | 2192 | # considered implementing a dependency just on the interface type |
michael@0 | 2193 | # file, but then every modification to an interface would cause this |
michael@0 | 2194 | # to be regenerated which is still undesirable. We decided not to |
michael@0 | 2195 | # depend on anything, reasoning that: |
michael@0 | 2196 | # 1) Changing the concrete type of the interface requires modifying |
michael@0 | 2197 | # Bindings.conf, which is still a global dependency. |
michael@0 | 2198 | # 2) Changing an interface to a dictionary (or vice versa) with the |
michael@0 | 2199 | # same identifier should be incredibly rare. |
michael@0 | 2200 | return set() |
michael@0 | 2201 | |
michael@0 | 2202 | class IDLBuiltinType(IDLType): |
michael@0 | 2203 | |
michael@0 | 2204 | Types = enum( |
michael@0 | 2205 | # The integer types |
michael@0 | 2206 | 'byte', |
michael@0 | 2207 | 'octet', |
michael@0 | 2208 | 'short', |
michael@0 | 2209 | 'unsigned_short', |
michael@0 | 2210 | 'long', |
michael@0 | 2211 | 'unsigned_long', |
michael@0 | 2212 | 'long_long', |
michael@0 | 2213 | 'unsigned_long_long', |
michael@0 | 2214 | # Additional primitive types |
michael@0 | 2215 | 'boolean', |
michael@0 | 2216 | 'unrestricted_float', |
michael@0 | 2217 | 'float', |
michael@0 | 2218 | 'unrestricted_double', |
michael@0 | 2219 | # IMPORTANT: "double" must be the last primitive type listed |
michael@0 | 2220 | 'double', |
michael@0 | 2221 | # Other types |
michael@0 | 2222 | 'any', |
michael@0 | 2223 | 'domstring', |
michael@0 | 2224 | 'bytestring', |
michael@0 | 2225 | 'object', |
michael@0 | 2226 | 'date', |
michael@0 | 2227 | 'void', |
michael@0 | 2228 | # Funny stuff |
michael@0 | 2229 | 'ArrayBuffer', |
michael@0 | 2230 | 'ArrayBufferView', |
michael@0 | 2231 | 'Int8Array', |
michael@0 | 2232 | 'Uint8Array', |
michael@0 | 2233 | 'Uint8ClampedArray', |
michael@0 | 2234 | 'Int16Array', |
michael@0 | 2235 | 'Uint16Array', |
michael@0 | 2236 | 'Int32Array', |
michael@0 | 2237 | 'Uint32Array', |
michael@0 | 2238 | 'Float32Array', |
michael@0 | 2239 | 'Float64Array' |
michael@0 | 2240 | ) |
michael@0 | 2241 | |
michael@0 | 2242 | TagLookup = { |
michael@0 | 2243 | Types.byte: IDLType.Tags.int8, |
michael@0 | 2244 | Types.octet: IDLType.Tags.uint8, |
michael@0 | 2245 | Types.short: IDLType.Tags.int16, |
michael@0 | 2246 | Types.unsigned_short: IDLType.Tags.uint16, |
michael@0 | 2247 | Types.long: IDLType.Tags.int32, |
michael@0 | 2248 | Types.unsigned_long: IDLType.Tags.uint32, |
michael@0 | 2249 | Types.long_long: IDLType.Tags.int64, |
michael@0 | 2250 | Types.unsigned_long_long: IDLType.Tags.uint64, |
michael@0 | 2251 | Types.boolean: IDLType.Tags.bool, |
michael@0 | 2252 | Types.unrestricted_float: IDLType.Tags.unrestricted_float, |
michael@0 | 2253 | Types.float: IDLType.Tags.float, |
michael@0 | 2254 | Types.unrestricted_double: IDLType.Tags.unrestricted_double, |
michael@0 | 2255 | Types.double: IDLType.Tags.double, |
michael@0 | 2256 | Types.any: IDLType.Tags.any, |
michael@0 | 2257 | Types.domstring: IDLType.Tags.domstring, |
michael@0 | 2258 | Types.bytestring: IDLType.Tags.bytestring, |
michael@0 | 2259 | Types.object: IDLType.Tags.object, |
michael@0 | 2260 | Types.date: IDLType.Tags.date, |
michael@0 | 2261 | Types.void: IDLType.Tags.void, |
michael@0 | 2262 | Types.ArrayBuffer: IDLType.Tags.interface, |
michael@0 | 2263 | Types.ArrayBufferView: IDLType.Tags.interface, |
michael@0 | 2264 | Types.Int8Array: IDLType.Tags.interface, |
michael@0 | 2265 | Types.Uint8Array: IDLType.Tags.interface, |
michael@0 | 2266 | Types.Uint8ClampedArray: IDLType.Tags.interface, |
michael@0 | 2267 | Types.Int16Array: IDLType.Tags.interface, |
michael@0 | 2268 | Types.Uint16Array: IDLType.Tags.interface, |
michael@0 | 2269 | Types.Int32Array: IDLType.Tags.interface, |
michael@0 | 2270 | Types.Uint32Array: IDLType.Tags.interface, |
michael@0 | 2271 | Types.Float32Array: IDLType.Tags.interface, |
michael@0 | 2272 | Types.Float64Array: IDLType.Tags.interface |
michael@0 | 2273 | } |
michael@0 | 2274 | |
michael@0 | 2275 | def __init__(self, location, name, type): |
michael@0 | 2276 | IDLType.__init__(self, location, name) |
michael@0 | 2277 | self.builtin = True |
michael@0 | 2278 | self._typeTag = type |
michael@0 | 2279 | |
michael@0 | 2280 | def isPrimitive(self): |
michael@0 | 2281 | return self._typeTag <= IDLBuiltinType.Types.double |
michael@0 | 2282 | |
michael@0 | 2283 | def isBoolean(self): |
michael@0 | 2284 | return self._typeTag == IDLBuiltinType.Types.boolean |
michael@0 | 2285 | |
michael@0 | 2286 | def isNumeric(self): |
michael@0 | 2287 | return self.isPrimitive() and not self.isBoolean() |
michael@0 | 2288 | |
michael@0 | 2289 | def isString(self): |
michael@0 | 2290 | return self._typeTag == IDLBuiltinType.Types.domstring or \ |
michael@0 | 2291 | self._typeTag == IDLBuiltinType.Types.bytestring |
michael@0 | 2292 | |
michael@0 | 2293 | def isByteString(self): |
michael@0 | 2294 | return self._typeTag == IDLBuiltinType.Types.bytestring |
michael@0 | 2295 | |
michael@0 | 2296 | def isDOMString(self): |
michael@0 | 2297 | return self._typeTag == IDLBuiltinType.Types.domstring |
michael@0 | 2298 | |
michael@0 | 2299 | def isInteger(self): |
michael@0 | 2300 | return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long |
michael@0 | 2301 | |
michael@0 | 2302 | def isArrayBuffer(self): |
michael@0 | 2303 | return self._typeTag == IDLBuiltinType.Types.ArrayBuffer |
michael@0 | 2304 | |
michael@0 | 2305 | def isArrayBufferView(self): |
michael@0 | 2306 | return self._typeTag == IDLBuiltinType.Types.ArrayBufferView |
michael@0 | 2307 | |
michael@0 | 2308 | def isTypedArray(self): |
michael@0 | 2309 | return self._typeTag >= IDLBuiltinType.Types.Int8Array and \ |
michael@0 | 2310 | self._typeTag <= IDLBuiltinType.Types.Float64Array |
michael@0 | 2311 | |
michael@0 | 2312 | def isInterface(self): |
michael@0 | 2313 | # TypedArray things are interface types per the TypedArray spec, |
michael@0 | 2314 | # but we handle them as builtins because SpiderMonkey implements |
michael@0 | 2315 | # all of it internally. |
michael@0 | 2316 | return self.isArrayBuffer() or \ |
michael@0 | 2317 | self.isArrayBufferView() or \ |
michael@0 | 2318 | self.isTypedArray() |
michael@0 | 2319 | |
michael@0 | 2320 | def isNonCallbackInterface(self): |
michael@0 | 2321 | # All the interfaces we can be are non-callback |
michael@0 | 2322 | return self.isInterface() |
michael@0 | 2323 | |
michael@0 | 2324 | def isFloat(self): |
michael@0 | 2325 | return self._typeTag == IDLBuiltinType.Types.float or \ |
michael@0 | 2326 | self._typeTag == IDLBuiltinType.Types.double or \ |
michael@0 | 2327 | self._typeTag == IDLBuiltinType.Types.unrestricted_float or \ |
michael@0 | 2328 | self._typeTag == IDLBuiltinType.Types.unrestricted_double |
michael@0 | 2329 | |
michael@0 | 2330 | def isUnrestricted(self): |
michael@0 | 2331 | assert self.isFloat() |
michael@0 | 2332 | return self._typeTag == IDLBuiltinType.Types.unrestricted_float or \ |
michael@0 | 2333 | self._typeTag == IDLBuiltinType.Types.unrestricted_double |
michael@0 | 2334 | |
michael@0 | 2335 | def isSerializable(self): |
michael@0 | 2336 | return self.isPrimitive() or self.isDOMString() or self.isDate() |
michael@0 | 2337 | |
michael@0 | 2338 | def includesRestrictedFloat(self): |
michael@0 | 2339 | return self.isFloat() and not self.isUnrestricted() |
michael@0 | 2340 | |
michael@0 | 2341 | def tag(self): |
michael@0 | 2342 | return IDLBuiltinType.TagLookup[self._typeTag] |
michael@0 | 2343 | |
michael@0 | 2344 | def isDistinguishableFrom(self, other): |
michael@0 | 2345 | if other.isUnion(): |
michael@0 | 2346 | # Just forward to the union; it'll deal |
michael@0 | 2347 | return other.isDistinguishableFrom(self) |
michael@0 | 2348 | if self.isBoolean(): |
michael@0 | 2349 | return (other.isNumeric() or other.isString() or other.isEnum() or |
michael@0 | 2350 | other.isInterface() or other.isObject() or |
michael@0 | 2351 | other.isCallback() or other.isDictionary() or |
michael@0 | 2352 | other.isSequence() or other.isMozMap() or other.isArray() or |
michael@0 | 2353 | other.isDate()) |
michael@0 | 2354 | if self.isNumeric(): |
michael@0 | 2355 | return (other.isBoolean() or other.isString() or other.isEnum() or |
michael@0 | 2356 | other.isInterface() or other.isObject() or |
michael@0 | 2357 | other.isCallback() or other.isDictionary() or |
michael@0 | 2358 | other.isSequence() or other.isMozMap() or other.isArray() or |
michael@0 | 2359 | other.isDate()) |
michael@0 | 2360 | if self.isString(): |
michael@0 | 2361 | return (other.isPrimitive() or other.isInterface() or |
michael@0 | 2362 | other.isObject() or |
michael@0 | 2363 | other.isCallback() or other.isDictionary() or |
michael@0 | 2364 | other.isSequence() or other.isMozMap() or other.isArray() or |
michael@0 | 2365 | other.isDate()) |
michael@0 | 2366 | if self.isAny(): |
michael@0 | 2367 | # Can't tell "any" apart from anything |
michael@0 | 2368 | return False |
michael@0 | 2369 | if self.isObject(): |
michael@0 | 2370 | return other.isPrimitive() or other.isString() or other.isEnum() |
michael@0 | 2371 | if self.isDate(): |
michael@0 | 2372 | return (other.isPrimitive() or other.isString() or other.isEnum() or |
michael@0 | 2373 | other.isInterface() or other.isCallback() or |
michael@0 | 2374 | other.isDictionary() or other.isSequence() or |
michael@0 | 2375 | other.isMozMap() or other.isArray()) |
michael@0 | 2376 | if self.isVoid(): |
michael@0 | 2377 | return not other.isVoid() |
michael@0 | 2378 | # Not much else we could be! |
michael@0 | 2379 | assert self.isSpiderMonkeyInterface() |
michael@0 | 2380 | # Like interfaces, but we know we're not a callback |
michael@0 | 2381 | return (other.isPrimitive() or other.isString() or other.isEnum() or |
michael@0 | 2382 | other.isCallback() or other.isDictionary() or |
michael@0 | 2383 | other.isSequence() or other.isMozMap() or other.isArray() or |
michael@0 | 2384 | other.isDate() or |
michael@0 | 2385 | (other.isInterface() and ( |
michael@0 | 2386 | # ArrayBuffer is distinguishable from everything |
michael@0 | 2387 | # that's not an ArrayBuffer or a callback interface |
michael@0 | 2388 | (self.isArrayBuffer() and not other.isArrayBuffer()) or |
michael@0 | 2389 | # ArrayBufferView is distinguishable from everything |
michael@0 | 2390 | # that's not an ArrayBufferView or typed array. |
michael@0 | 2391 | (self.isArrayBufferView() and not other.isArrayBufferView() and |
michael@0 | 2392 | not other.isTypedArray()) or |
michael@0 | 2393 | # Typed arrays are distinguishable from everything |
michael@0 | 2394 | # except ArrayBufferView and the same type of typed |
michael@0 | 2395 | # array |
michael@0 | 2396 | (self.isTypedArray() and not other.isArrayBufferView() and not |
michael@0 | 2397 | (other.isTypedArray() and other.name == self.name))))) |
michael@0 | 2398 | |
michael@0 | 2399 | def _getDependentObjects(self): |
michael@0 | 2400 | return set() |
michael@0 | 2401 | |
michael@0 | 2402 | BuiltinTypes = { |
michael@0 | 2403 | IDLBuiltinType.Types.byte: |
michael@0 | 2404 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte", |
michael@0 | 2405 | IDLBuiltinType.Types.byte), |
michael@0 | 2406 | IDLBuiltinType.Types.octet: |
michael@0 | 2407 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Octet", |
michael@0 | 2408 | IDLBuiltinType.Types.octet), |
michael@0 | 2409 | IDLBuiltinType.Types.short: |
michael@0 | 2410 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Short", |
michael@0 | 2411 | IDLBuiltinType.Types.short), |
michael@0 | 2412 | IDLBuiltinType.Types.unsigned_short: |
michael@0 | 2413 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedShort", |
michael@0 | 2414 | IDLBuiltinType.Types.unsigned_short), |
michael@0 | 2415 | IDLBuiltinType.Types.long: |
michael@0 | 2416 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Long", |
michael@0 | 2417 | IDLBuiltinType.Types.long), |
michael@0 | 2418 | IDLBuiltinType.Types.unsigned_long: |
michael@0 | 2419 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedLong", |
michael@0 | 2420 | IDLBuiltinType.Types.unsigned_long), |
michael@0 | 2421 | IDLBuiltinType.Types.long_long: |
michael@0 | 2422 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "LongLong", |
michael@0 | 2423 | IDLBuiltinType.Types.long_long), |
michael@0 | 2424 | IDLBuiltinType.Types.unsigned_long_long: |
michael@0 | 2425 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedLongLong", |
michael@0 | 2426 | IDLBuiltinType.Types.unsigned_long_long), |
michael@0 | 2427 | IDLBuiltinType.Types.boolean: |
michael@0 | 2428 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Boolean", |
michael@0 | 2429 | IDLBuiltinType.Types.boolean), |
michael@0 | 2430 | IDLBuiltinType.Types.float: |
michael@0 | 2431 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float", |
michael@0 | 2432 | IDLBuiltinType.Types.float), |
michael@0 | 2433 | IDLBuiltinType.Types.unrestricted_float: |
michael@0 | 2434 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnrestrictedFloat", |
michael@0 | 2435 | IDLBuiltinType.Types.unrestricted_float), |
michael@0 | 2436 | IDLBuiltinType.Types.double: |
michael@0 | 2437 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Double", |
michael@0 | 2438 | IDLBuiltinType.Types.double), |
michael@0 | 2439 | IDLBuiltinType.Types.unrestricted_double: |
michael@0 | 2440 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnrestrictedDouble", |
michael@0 | 2441 | IDLBuiltinType.Types.unrestricted_double), |
michael@0 | 2442 | IDLBuiltinType.Types.any: |
michael@0 | 2443 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Any", |
michael@0 | 2444 | IDLBuiltinType.Types.any), |
michael@0 | 2445 | IDLBuiltinType.Types.domstring: |
michael@0 | 2446 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "String", |
michael@0 | 2447 | IDLBuiltinType.Types.domstring), |
michael@0 | 2448 | IDLBuiltinType.Types.bytestring: |
michael@0 | 2449 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "ByteString", |
michael@0 | 2450 | IDLBuiltinType.Types.bytestring), |
michael@0 | 2451 | IDLBuiltinType.Types.object: |
michael@0 | 2452 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Object", |
michael@0 | 2453 | IDLBuiltinType.Types.object), |
michael@0 | 2454 | IDLBuiltinType.Types.date: |
michael@0 | 2455 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Date", |
michael@0 | 2456 | IDLBuiltinType.Types.date), |
michael@0 | 2457 | IDLBuiltinType.Types.void: |
michael@0 | 2458 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Void", |
michael@0 | 2459 | IDLBuiltinType.Types.void), |
michael@0 | 2460 | IDLBuiltinType.Types.ArrayBuffer: |
michael@0 | 2461 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBuffer", |
michael@0 | 2462 | IDLBuiltinType.Types.ArrayBuffer), |
michael@0 | 2463 | IDLBuiltinType.Types.ArrayBufferView: |
michael@0 | 2464 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBufferView", |
michael@0 | 2465 | IDLBuiltinType.Types.ArrayBufferView), |
michael@0 | 2466 | IDLBuiltinType.Types.Int8Array: |
michael@0 | 2467 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int8Array", |
michael@0 | 2468 | IDLBuiltinType.Types.Int8Array), |
michael@0 | 2469 | IDLBuiltinType.Types.Uint8Array: |
michael@0 | 2470 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint8Array", |
michael@0 | 2471 | IDLBuiltinType.Types.Uint8Array), |
michael@0 | 2472 | IDLBuiltinType.Types.Uint8ClampedArray: |
michael@0 | 2473 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint8ClampedArray", |
michael@0 | 2474 | IDLBuiltinType.Types.Uint8ClampedArray), |
michael@0 | 2475 | IDLBuiltinType.Types.Int16Array: |
michael@0 | 2476 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int16Array", |
michael@0 | 2477 | IDLBuiltinType.Types.Int16Array), |
michael@0 | 2478 | IDLBuiltinType.Types.Uint16Array: |
michael@0 | 2479 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint16Array", |
michael@0 | 2480 | IDLBuiltinType.Types.Uint16Array), |
michael@0 | 2481 | IDLBuiltinType.Types.Int32Array: |
michael@0 | 2482 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int32Array", |
michael@0 | 2483 | IDLBuiltinType.Types.Int32Array), |
michael@0 | 2484 | IDLBuiltinType.Types.Uint32Array: |
michael@0 | 2485 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint32Array", |
michael@0 | 2486 | IDLBuiltinType.Types.Uint32Array), |
michael@0 | 2487 | IDLBuiltinType.Types.Float32Array: |
michael@0 | 2488 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float32Array", |
michael@0 | 2489 | IDLBuiltinType.Types.Float32Array), |
michael@0 | 2490 | IDLBuiltinType.Types.Float64Array: |
michael@0 | 2491 | IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float64Array", |
michael@0 | 2492 | IDLBuiltinType.Types.Float64Array) |
michael@0 | 2493 | } |
michael@0 | 2494 | |
michael@0 | 2495 | |
michael@0 | 2496 | integerTypeSizes = { |
michael@0 | 2497 | IDLBuiltinType.Types.byte: (-128, 127), |
michael@0 | 2498 | IDLBuiltinType.Types.octet: (0, 255), |
michael@0 | 2499 | IDLBuiltinType.Types.short: (-32768, 32767), |
michael@0 | 2500 | IDLBuiltinType.Types.unsigned_short: (0, 65535), |
michael@0 | 2501 | IDLBuiltinType.Types.long: (-2147483648, 2147483647), |
michael@0 | 2502 | IDLBuiltinType.Types.unsigned_long: (0, 4294967295), |
michael@0 | 2503 | IDLBuiltinType.Types.long_long: (-9223372036854775808, |
michael@0 | 2504 | 9223372036854775807), |
michael@0 | 2505 | IDLBuiltinType.Types.unsigned_long_long: (0, 18446744073709551615) |
michael@0 | 2506 | } |
michael@0 | 2507 | |
michael@0 | 2508 | def matchIntegerValueToType(value): |
michael@0 | 2509 | for type, extremes in integerTypeSizes.items(): |
michael@0 | 2510 | (min, max) = extremes |
michael@0 | 2511 | if value <= max and value >= min: |
michael@0 | 2512 | return BuiltinTypes[type] |
michael@0 | 2513 | |
michael@0 | 2514 | return None |
michael@0 | 2515 | |
michael@0 | 2516 | class IDLValue(IDLObject): |
michael@0 | 2517 | def __init__(self, location, type, value): |
michael@0 | 2518 | IDLObject.__init__(self, location) |
michael@0 | 2519 | self.type = type |
michael@0 | 2520 | assert isinstance(type, IDLType) |
michael@0 | 2521 | |
michael@0 | 2522 | self.value = value |
michael@0 | 2523 | |
michael@0 | 2524 | def coerceToType(self, type, location): |
michael@0 | 2525 | if type == self.type: |
michael@0 | 2526 | return self # Nothing to do |
michael@0 | 2527 | |
michael@0 | 2528 | # We first check for unions to ensure that even if the union is nullable |
michael@0 | 2529 | # we end up with the right flat member type, not the union's type. |
michael@0 | 2530 | if type.isUnion(): |
michael@0 | 2531 | # We use the flat member types here, because if we have a nullable |
michael@0 | 2532 | # member type, or a nested union, we want the type the value |
michael@0 | 2533 | # actually coerces to, not the nullable or nested union type. |
michael@0 | 2534 | for subtype in type.unroll().flatMemberTypes: |
michael@0 | 2535 | try: |
michael@0 | 2536 | coercedValue = self.coerceToType(subtype, location) |
michael@0 | 2537 | # Create a new IDLValue to make sure that we have the |
michael@0 | 2538 | # correct float/double type. This is necessary because we |
michael@0 | 2539 | # use the value's type when it is a default value of a |
michael@0 | 2540 | # union, and the union cares about the exact float type. |
michael@0 | 2541 | return IDLValue(self.location, subtype, coercedValue.value) |
michael@0 | 2542 | except: |
michael@0 | 2543 | pass |
michael@0 | 2544 | # If the type allows null, rerun this matching on the inner type, except |
michael@0 | 2545 | # nullable enums. We handle those specially, because we want our |
michael@0 | 2546 | # default string values to stay strings even when assigned to a nullable |
michael@0 | 2547 | # enum. |
michael@0 | 2548 | elif type.nullable() and not type.isEnum(): |
michael@0 | 2549 | innerValue = self.coerceToType(type.inner, location) |
michael@0 | 2550 | return IDLValue(self.location, type, innerValue.value) |
michael@0 | 2551 | |
michael@0 | 2552 | elif self.type.isInteger() and type.isInteger(): |
michael@0 | 2553 | # We're both integer types. See if we fit. |
michael@0 | 2554 | |
michael@0 | 2555 | (min, max) = integerTypeSizes[type._typeTag] |
michael@0 | 2556 | if self.value <= max and self.value >= min: |
michael@0 | 2557 | # Promote |
michael@0 | 2558 | return IDLValue(self.location, type, self.value) |
michael@0 | 2559 | else: |
michael@0 | 2560 | raise WebIDLError("Value %s is out of range for type %s." % |
michael@0 | 2561 | (self.value, type), [location]) |
michael@0 | 2562 | elif self.type.isInteger() and type.isFloat(): |
michael@0 | 2563 | # Convert an integer literal into float |
michael@0 | 2564 | if -2**24 <= self.value <= 2**24: |
michael@0 | 2565 | floatType = BuiltinTypes[IDLBuiltinType.Types.float] |
michael@0 | 2566 | return IDLValue(self.location, floatType, float(self.value)) |
michael@0 | 2567 | else: |
michael@0 | 2568 | raise WebIDLError("Converting value %s to %s will lose precision." % |
michael@0 | 2569 | (self.value, type), [location]) |
michael@0 | 2570 | elif self.type.isString() and type.isEnum(): |
michael@0 | 2571 | # Just keep our string, but make sure it's a valid value for this enum |
michael@0 | 2572 | enum = type.unroll().inner |
michael@0 | 2573 | if self.value not in enum.values(): |
michael@0 | 2574 | raise WebIDLError("'%s' is not a valid default value for enum %s" |
michael@0 | 2575 | % (self.value, enum.identifier.name), |
michael@0 | 2576 | [location, enum.location]) |
michael@0 | 2577 | return self |
michael@0 | 2578 | elif self.type.isFloat() and type.isFloat(): |
michael@0 | 2579 | if (not type.isUnrestricted() and |
michael@0 | 2580 | (self.value == float("inf") or self.value == float("-inf") or |
michael@0 | 2581 | math.isnan(self.value))): |
michael@0 | 2582 | raise WebIDLError("Trying to convert unrestricted value %s to non-unrestricted" |
michael@0 | 2583 | % self.value, [location]); |
michael@0 | 2584 | return self |
michael@0 | 2585 | raise WebIDLError("Cannot coerce type %s to type %s." % |
michael@0 | 2586 | (self.type, type), [location]) |
michael@0 | 2587 | |
michael@0 | 2588 | def _getDependentObjects(self): |
michael@0 | 2589 | return set() |
michael@0 | 2590 | |
michael@0 | 2591 | class IDLNullValue(IDLObject): |
michael@0 | 2592 | def __init__(self, location): |
michael@0 | 2593 | IDLObject.__init__(self, location) |
michael@0 | 2594 | self.type = None |
michael@0 | 2595 | self.value = None |
michael@0 | 2596 | |
michael@0 | 2597 | def coerceToType(self, type, location): |
michael@0 | 2598 | if (not isinstance(type, IDLNullableType) and |
michael@0 | 2599 | not (type.isUnion() and type.hasNullableType) and |
michael@0 | 2600 | not (type.isUnion() and type.hasDictionaryType) and |
michael@0 | 2601 | not type.isDictionary() and |
michael@0 | 2602 | not type.isAny()): |
michael@0 | 2603 | raise WebIDLError("Cannot coerce null value to type %s." % type, |
michael@0 | 2604 | [location]) |
michael@0 | 2605 | |
michael@0 | 2606 | nullValue = IDLNullValue(self.location) |
michael@0 | 2607 | if type.isUnion() and not type.nullable() and type.hasDictionaryType: |
michael@0 | 2608 | # We're actually a default value for the union's dictionary member. |
michael@0 | 2609 | # Use its type. |
michael@0 | 2610 | for t in type.flatMemberTypes: |
michael@0 | 2611 | if t.isDictionary(): |
michael@0 | 2612 | nullValue.type = t |
michael@0 | 2613 | return nullValue |
michael@0 | 2614 | nullValue.type = type |
michael@0 | 2615 | return nullValue |
michael@0 | 2616 | |
michael@0 | 2617 | def _getDependentObjects(self): |
michael@0 | 2618 | return set() |
michael@0 | 2619 | |
michael@0 | 2620 | class IDLUndefinedValue(IDLObject): |
michael@0 | 2621 | def __init__(self, location): |
michael@0 | 2622 | IDLObject.__init__(self, location) |
michael@0 | 2623 | self.type = None |
michael@0 | 2624 | self.value = None |
michael@0 | 2625 | |
michael@0 | 2626 | def coerceToType(self, type, location): |
michael@0 | 2627 | if not type.isAny(): |
michael@0 | 2628 | raise WebIDLError("Cannot coerce undefined value to type %s." % type, |
michael@0 | 2629 | [location]) |
michael@0 | 2630 | |
michael@0 | 2631 | undefinedValue = IDLUndefinedValue(self.location) |
michael@0 | 2632 | undefinedValue.type = type |
michael@0 | 2633 | return undefinedValue |
michael@0 | 2634 | |
michael@0 | 2635 | def _getDependentObjects(self): |
michael@0 | 2636 | return set() |
michael@0 | 2637 | |
michael@0 | 2638 | class IDLInterfaceMember(IDLObjectWithIdentifier): |
michael@0 | 2639 | |
michael@0 | 2640 | Tags = enum( |
michael@0 | 2641 | 'Const', |
michael@0 | 2642 | 'Attr', |
michael@0 | 2643 | 'Method' |
michael@0 | 2644 | ) |
michael@0 | 2645 | |
michael@0 | 2646 | Special = enum( |
michael@0 | 2647 | 'Static', |
michael@0 | 2648 | 'Stringifier' |
michael@0 | 2649 | ) |
michael@0 | 2650 | |
michael@0 | 2651 | def __init__(self, location, identifier, tag): |
michael@0 | 2652 | IDLObjectWithIdentifier.__init__(self, location, None, identifier) |
michael@0 | 2653 | self.tag = tag |
michael@0 | 2654 | self._extendedAttrDict = {} |
michael@0 | 2655 | |
michael@0 | 2656 | def isMethod(self): |
michael@0 | 2657 | return self.tag == IDLInterfaceMember.Tags.Method |
michael@0 | 2658 | |
michael@0 | 2659 | def isAttr(self): |
michael@0 | 2660 | return self.tag == IDLInterfaceMember.Tags.Attr |
michael@0 | 2661 | |
michael@0 | 2662 | def isConst(self): |
michael@0 | 2663 | return self.tag == IDLInterfaceMember.Tags.Const |
michael@0 | 2664 | |
michael@0 | 2665 | def addExtendedAttributes(self, attrs): |
michael@0 | 2666 | for attr in attrs: |
michael@0 | 2667 | self.handleExtendedAttribute(attr) |
michael@0 | 2668 | attrlist = attr.listValue() |
michael@0 | 2669 | self._extendedAttrDict[attr.identifier()] = attrlist if len(attrlist) else True |
michael@0 | 2670 | |
michael@0 | 2671 | def handleExtendedAttribute(self, attr): |
michael@0 | 2672 | pass |
michael@0 | 2673 | |
michael@0 | 2674 | def getExtendedAttribute(self, name): |
michael@0 | 2675 | return self._extendedAttrDict.get(name, None) |
michael@0 | 2676 | |
michael@0 | 2677 | class IDLConst(IDLInterfaceMember): |
michael@0 | 2678 | def __init__(self, location, identifier, type, value): |
michael@0 | 2679 | IDLInterfaceMember.__init__(self, location, identifier, |
michael@0 | 2680 | IDLInterfaceMember.Tags.Const) |
michael@0 | 2681 | |
michael@0 | 2682 | assert isinstance(type, IDLType) |
michael@0 | 2683 | if type.isDictionary(): |
michael@0 | 2684 | raise WebIDLError("A constant cannot be of a dictionary type", |
michael@0 | 2685 | [self.location]) |
michael@0 | 2686 | self.type = type |
michael@0 | 2687 | self.value = value |
michael@0 | 2688 | |
michael@0 | 2689 | if identifier.name == "prototype": |
michael@0 | 2690 | raise WebIDLError("The identifier of a constant must not be 'prototype'", |
michael@0 | 2691 | [location]) |
michael@0 | 2692 | |
michael@0 | 2693 | def __str__(self): |
michael@0 | 2694 | return "'%s' const '%s'" % (self.type, self.identifier) |
michael@0 | 2695 | |
michael@0 | 2696 | def finish(self, scope): |
michael@0 | 2697 | if not self.type.isComplete(): |
michael@0 | 2698 | type = self.type.complete(scope) |
michael@0 | 2699 | if not type.isPrimitive() and not type.isString(): |
michael@0 | 2700 | locations = [self.type.location, type.location] |
michael@0 | 2701 | try: |
michael@0 | 2702 | locations.append(type.inner.location) |
michael@0 | 2703 | except: |
michael@0 | 2704 | pass |
michael@0 | 2705 | raise WebIDLError("Incorrect type for constant", locations) |
michael@0 | 2706 | self.type = type |
michael@0 | 2707 | |
michael@0 | 2708 | # The value might not match the type |
michael@0 | 2709 | coercedValue = self.value.coerceToType(self.type, self.location) |
michael@0 | 2710 | assert coercedValue |
michael@0 | 2711 | |
michael@0 | 2712 | self.value = coercedValue |
michael@0 | 2713 | |
michael@0 | 2714 | def validate(self): |
michael@0 | 2715 | pass |
michael@0 | 2716 | |
michael@0 | 2717 | def _getDependentObjects(self): |
michael@0 | 2718 | return set([self.type, self.value]) |
michael@0 | 2719 | |
michael@0 | 2720 | class IDLAttribute(IDLInterfaceMember): |
michael@0 | 2721 | def __init__(self, location, identifier, type, readonly, inherit=False, |
michael@0 | 2722 | static=False, stringifier=False): |
michael@0 | 2723 | IDLInterfaceMember.__init__(self, location, identifier, |
michael@0 | 2724 | IDLInterfaceMember.Tags.Attr) |
michael@0 | 2725 | |
michael@0 | 2726 | assert isinstance(type, IDLType) |
michael@0 | 2727 | self.type = type |
michael@0 | 2728 | self.readonly = readonly |
michael@0 | 2729 | self.inherit = inherit |
michael@0 | 2730 | self.static = static |
michael@0 | 2731 | self.lenientThis = False |
michael@0 | 2732 | self._unforgeable = False |
michael@0 | 2733 | self.stringifier = stringifier |
michael@0 | 2734 | self.enforceRange = False |
michael@0 | 2735 | self.clamp = False |
michael@0 | 2736 | self.slotIndex = None |
michael@0 | 2737 | |
michael@0 | 2738 | if static and identifier.name == "prototype": |
michael@0 | 2739 | raise WebIDLError("The identifier of a static attribute must not be 'prototype'", |
michael@0 | 2740 | [location]) |
michael@0 | 2741 | |
michael@0 | 2742 | if readonly and inherit: |
michael@0 | 2743 | raise WebIDLError("An attribute cannot be both 'readonly' and 'inherit'", |
michael@0 | 2744 | [self.location]) |
michael@0 | 2745 | |
michael@0 | 2746 | def isStatic(self): |
michael@0 | 2747 | return self.static |
michael@0 | 2748 | |
michael@0 | 2749 | def __str__(self): |
michael@0 | 2750 | return "'%s' attribute '%s'" % (self.type, self.identifier) |
michael@0 | 2751 | |
michael@0 | 2752 | def finish(self, scope): |
michael@0 | 2753 | if not self.type.isComplete(): |
michael@0 | 2754 | t = self.type.complete(scope) |
michael@0 | 2755 | |
michael@0 | 2756 | assert not isinstance(t, IDLUnresolvedType) |
michael@0 | 2757 | assert not isinstance(t, IDLTypedefType) |
michael@0 | 2758 | assert not isinstance(t.name, IDLUnresolvedIdentifier) |
michael@0 | 2759 | self.type = t |
michael@0 | 2760 | |
michael@0 | 2761 | if self.type.isDictionary() and not self.getExtendedAttribute("Cached"): |
michael@0 | 2762 | raise WebIDLError("An attribute cannot be of a dictionary type", |
michael@0 | 2763 | [self.location]) |
michael@0 | 2764 | if self.type.isSequence() and not self.getExtendedAttribute("Cached"): |
michael@0 | 2765 | raise WebIDLError("A non-cached attribute cannot be of a sequence " |
michael@0 | 2766 | "type", [self.location]) |
michael@0 | 2767 | if self.type.isMozMap() and not self.getExtendedAttribute("Cached"): |
michael@0 | 2768 | raise WebIDLError("A non-cached attribute cannot be of a MozMap " |
michael@0 | 2769 | "type", [self.location]) |
michael@0 | 2770 | if self.type.isUnion(): |
michael@0 | 2771 | for f in self.type.unroll().flatMemberTypes: |
michael@0 | 2772 | if f.isDictionary(): |
michael@0 | 2773 | raise WebIDLError("An attribute cannot be of a union " |
michael@0 | 2774 | "type if one of its member types (or " |
michael@0 | 2775 | "one of its member types's member " |
michael@0 | 2776 | "types, and so on) is a dictionary " |
michael@0 | 2777 | "type", [self.location, f.location]) |
michael@0 | 2778 | if f.isSequence(): |
michael@0 | 2779 | raise WebIDLError("An attribute cannot be of a union " |
michael@0 | 2780 | "type if one of its member types (or " |
michael@0 | 2781 | "one of its member types's member " |
michael@0 | 2782 | "types, and so on) is a sequence " |
michael@0 | 2783 | "type", [self.location, f.location]) |
michael@0 | 2784 | if f.isMozMap(): |
michael@0 | 2785 | raise WebIDLError("An attribute cannot be of a union " |
michael@0 | 2786 | "type if one of its member types (or " |
michael@0 | 2787 | "one of its member types's member " |
michael@0 | 2788 | "types, and so on) is a MozMap " |
michael@0 | 2789 | "type", [self.location, f.location]) |
michael@0 | 2790 | if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"): |
michael@0 | 2791 | raise WebIDLError("An attribute with [PutForwards] must have an " |
michael@0 | 2792 | "interface type as its type", [self.location]) |
michael@0 | 2793 | |
michael@0 | 2794 | if not self.type.isInterface() and self.getExtendedAttribute("SameObject"): |
michael@0 | 2795 | raise WebIDLError("An attribute with [SameObject] must have an " |
michael@0 | 2796 | "interface type as its type", [self.location]) |
michael@0 | 2797 | |
michael@0 | 2798 | def validate(self): |
michael@0 | 2799 | if ((self.getExtendedAttribute("Cached") or |
michael@0 | 2800 | self.getExtendedAttribute("StoreInSlot")) and |
michael@0 | 2801 | not self.getExtendedAttribute("Constant") and |
michael@0 | 2802 | not self.getExtendedAttribute("Pure")): |
michael@0 | 2803 | raise WebIDLError("Cached attributes and attributes stored in " |
michael@0 | 2804 | "slots must be constant or pure, since the " |
michael@0 | 2805 | "getter won't always be called.", |
michael@0 | 2806 | [self.location]) |
michael@0 | 2807 | if self.getExtendedAttribute("Frozen"): |
michael@0 | 2808 | if (not self.type.isSequence() and not self.type.isDictionary() and |
michael@0 | 2809 | not self.type.isMozMap()): |
michael@0 | 2810 | raise WebIDLError("[Frozen] is only allowed on " |
michael@0 | 2811 | "sequence-valued, dictionary-valued, and " |
michael@0 | 2812 | "MozMap-valued attributes", |
michael@0 | 2813 | [self.location]) |
michael@0 | 2814 | |
michael@0 | 2815 | def handleExtendedAttribute(self, attr): |
michael@0 | 2816 | identifier = attr.identifier() |
michael@0 | 2817 | if identifier == "SetterThrows" and self.readonly: |
michael@0 | 2818 | raise WebIDLError("Readonly attributes must not be flagged as " |
michael@0 | 2819 | "[SetterThrows]", |
michael@0 | 2820 | [self.location]) |
michael@0 | 2821 | elif (((identifier == "Throws" or identifier == "GetterThrows") and |
michael@0 | 2822 | self.getExtendedAttribute("StoreInSlot")) or |
michael@0 | 2823 | (identifier == "StoreInSlot" and |
michael@0 | 2824 | (self.getExtendedAttribute("Throws") or |
michael@0 | 2825 | self.getExtendedAttribute("GetterThrows")))): |
michael@0 | 2826 | raise WebIDLError("Throwing things can't be [Pure] or [Constant] " |
michael@0 | 2827 | "or [SameObject] or [StoreInSlot]", |
michael@0 | 2828 | [attr.location]) |
michael@0 | 2829 | elif identifier == "LenientThis": |
michael@0 | 2830 | if not attr.noArguments(): |
michael@0 | 2831 | raise WebIDLError("[LenientThis] must take no arguments", |
michael@0 | 2832 | [attr.location]) |
michael@0 | 2833 | if self.isStatic(): |
michael@0 | 2834 | raise WebIDLError("[LenientThis] is only allowed on non-static " |
michael@0 | 2835 | "attributes", [attr.location, self.location]) |
michael@0 | 2836 | if self.getExtendedAttribute("CrossOriginReadable"): |
michael@0 | 2837 | raise WebIDLError("[LenientThis] is not allowed in combination " |
michael@0 | 2838 | "with [CrossOriginReadable]", |
michael@0 | 2839 | [attr.location, self.location]) |
michael@0 | 2840 | if self.getExtendedAttribute("CrossOriginWritable"): |
michael@0 | 2841 | raise WebIDLError("[LenientThis] is not allowed in combination " |
michael@0 | 2842 | "with [CrossOriginWritable]", |
michael@0 | 2843 | [attr.location, self.location]) |
michael@0 | 2844 | self.lenientThis = True |
michael@0 | 2845 | elif identifier == "Unforgeable": |
michael@0 | 2846 | if not self.readonly: |
michael@0 | 2847 | raise WebIDLError("[Unforgeable] is only allowed on readonly " |
michael@0 | 2848 | "attributes", [attr.location, self.location]) |
michael@0 | 2849 | if self.isStatic(): |
michael@0 | 2850 | raise WebIDLError("[Unforgeable] is only allowed on non-static " |
michael@0 | 2851 | "attributes", [attr.location, self.location]) |
michael@0 | 2852 | self._unforgeable = True |
michael@0 | 2853 | elif identifier == "SameObject" and not self.readonly: |
michael@0 | 2854 | raise WebIDLError("[SameObject] only allowed on readonly attributes", |
michael@0 | 2855 | [attr.location, self.location]) |
michael@0 | 2856 | elif identifier == "Constant" and not self.readonly: |
michael@0 | 2857 | raise WebIDLError("[Constant] only allowed on readonly attributes", |
michael@0 | 2858 | [attr.location, self.location]) |
michael@0 | 2859 | elif identifier == "PutForwards": |
michael@0 | 2860 | if not self.readonly: |
michael@0 | 2861 | raise WebIDLError("[PutForwards] is only allowed on readonly " |
michael@0 | 2862 | "attributes", [attr.location, self.location]) |
michael@0 | 2863 | if self.isStatic(): |
michael@0 | 2864 | raise WebIDLError("[PutForwards] is only allowed on non-static " |
michael@0 | 2865 | "attributes", [attr.location, self.location]) |
michael@0 | 2866 | if self.getExtendedAttribute("Replaceable") is not None: |
michael@0 | 2867 | raise WebIDLError("[PutForwards] and [Replaceable] can't both " |
michael@0 | 2868 | "appear on the same attribute", |
michael@0 | 2869 | [attr.location, self.location]) |
michael@0 | 2870 | if not attr.hasValue(): |
michael@0 | 2871 | raise WebIDLError("[PutForwards] takes an identifier", |
michael@0 | 2872 | [attr.location, self.location]) |
michael@0 | 2873 | elif identifier == "Replaceable": |
michael@0 | 2874 | if self.getExtendedAttribute("PutForwards") is not None: |
michael@0 | 2875 | raise WebIDLError("[PutForwards] and [Replaceable] can't both " |
michael@0 | 2876 | "appear on the same attribute", |
michael@0 | 2877 | [attr.location, self.location]) |
michael@0 | 2878 | elif identifier == "LenientFloat": |
michael@0 | 2879 | if self.readonly: |
michael@0 | 2880 | raise WebIDLError("[LenientFloat] used on a readonly attribute", |
michael@0 | 2881 | [attr.location, self.location]) |
michael@0 | 2882 | if not self.type.includesRestrictedFloat(): |
michael@0 | 2883 | raise WebIDLError("[LenientFloat] used on an attribute with a " |
michael@0 | 2884 | "non-restricted-float type", |
michael@0 | 2885 | [attr.location, self.location]) |
michael@0 | 2886 | elif identifier == "EnforceRange": |
michael@0 | 2887 | if self.readonly: |
michael@0 | 2888 | raise WebIDLError("[EnforceRange] used on a readonly attribute", |
michael@0 | 2889 | [attr.location, self.location]) |
michael@0 | 2890 | self.enforceRange = True |
michael@0 | 2891 | elif identifier == "Clamp": |
michael@0 | 2892 | if self.readonly: |
michael@0 | 2893 | raise WebIDLError("[Clamp] used on a readonly attribute", |
michael@0 | 2894 | [attr.location, self.location]) |
michael@0 | 2895 | self.clamp = True |
michael@0 | 2896 | elif identifier == "StoreInSlot": |
michael@0 | 2897 | if self.getExtendedAttribute("Cached"): |
michael@0 | 2898 | raise WebIDLError("[StoreInSlot] and [Cached] must not be " |
michael@0 | 2899 | "specified on the same attribute", |
michael@0 | 2900 | [attr.location, self.location]) |
michael@0 | 2901 | elif identifier == "Cached": |
michael@0 | 2902 | if self.getExtendedAttribute("StoreInSlot"): |
michael@0 | 2903 | raise WebIDLError("[Cached] and [StoreInSlot] must not be " |
michael@0 | 2904 | "specified on the same attribute", |
michael@0 | 2905 | [attr.location, self.location]) |
michael@0 | 2906 | elif (identifier == "CrossOriginReadable" or |
michael@0 | 2907 | identifier == "CrossOriginWritable"): |
michael@0 | 2908 | if not attr.noArguments(): |
michael@0 | 2909 | raise WebIDLError("[%s] must take no arguments" % identifier, |
michael@0 | 2910 | [attr.location]) |
michael@0 | 2911 | if self.isStatic(): |
michael@0 | 2912 | raise WebIDLError("[%s] is only allowed on non-static " |
michael@0 | 2913 | "attributes" % identifier, |
michael@0 | 2914 | [attr.location, self.location]) |
michael@0 | 2915 | if self.getExtendedAttribute("LenientThis"): |
michael@0 | 2916 | raise WebIDLError("[LenientThis] is not allowed in combination " |
michael@0 | 2917 | "with [%s]" % identifier, |
michael@0 | 2918 | [attr.location, self.location]) |
michael@0 | 2919 | elif (identifier == "Pref" or |
michael@0 | 2920 | identifier == "SetterThrows" or |
michael@0 | 2921 | identifier == "Pure" or |
michael@0 | 2922 | identifier == "Throws" or |
michael@0 | 2923 | identifier == "GetterThrows" or |
michael@0 | 2924 | identifier == "ChromeOnly" or |
michael@0 | 2925 | identifier == "SameObject" or |
michael@0 | 2926 | identifier == "Constant" or |
michael@0 | 2927 | identifier == "Func" or |
michael@0 | 2928 | identifier == "Frozen" or |
michael@0 | 2929 | identifier == "AvailableIn" or |
michael@0 | 2930 | identifier == "NewObject"): |
michael@0 | 2931 | # Known attributes that we don't need to do anything with here |
michael@0 | 2932 | pass |
michael@0 | 2933 | else: |
michael@0 | 2934 | raise WebIDLError("Unknown extended attribute %s on attribute" % identifier, |
michael@0 | 2935 | [attr.location]) |
michael@0 | 2936 | IDLInterfaceMember.handleExtendedAttribute(self, attr) |
michael@0 | 2937 | |
michael@0 | 2938 | def resolve(self, parentScope): |
michael@0 | 2939 | assert isinstance(parentScope, IDLScope) |
michael@0 | 2940 | self.type.resolveType(parentScope) |
michael@0 | 2941 | IDLObjectWithIdentifier.resolve(self, parentScope) |
michael@0 | 2942 | |
michael@0 | 2943 | def addExtendedAttributes(self, attrs): |
michael@0 | 2944 | attrs = self.checkForStringHandlingExtendedAttributes(attrs) |
michael@0 | 2945 | IDLInterfaceMember.addExtendedAttributes(self, attrs) |
michael@0 | 2946 | |
michael@0 | 2947 | def hasLenientThis(self): |
michael@0 | 2948 | return self.lenientThis |
michael@0 | 2949 | |
michael@0 | 2950 | def isUnforgeable(self): |
michael@0 | 2951 | return self._unforgeable |
michael@0 | 2952 | |
michael@0 | 2953 | def _getDependentObjects(self): |
michael@0 | 2954 | return set([self.type]) |
michael@0 | 2955 | |
michael@0 | 2956 | class IDLArgument(IDLObjectWithIdentifier): |
michael@0 | 2957 | def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False): |
michael@0 | 2958 | IDLObjectWithIdentifier.__init__(self, location, None, identifier) |
michael@0 | 2959 | |
michael@0 | 2960 | assert isinstance(type, IDLType) |
michael@0 | 2961 | self.type = type |
michael@0 | 2962 | |
michael@0 | 2963 | self.optional = optional |
michael@0 | 2964 | self.defaultValue = defaultValue |
michael@0 | 2965 | self.variadic = variadic |
michael@0 | 2966 | self.dictionaryMember = dictionaryMember |
michael@0 | 2967 | self._isComplete = False |
michael@0 | 2968 | self.enforceRange = False |
michael@0 | 2969 | self.clamp = False |
michael@0 | 2970 | self._allowTreatNonCallableAsNull = False |
michael@0 | 2971 | |
michael@0 | 2972 | assert not variadic or optional |
michael@0 | 2973 | |
michael@0 | 2974 | def addExtendedAttributes(self, attrs): |
michael@0 | 2975 | attrs = self.checkForStringHandlingExtendedAttributes( |
michael@0 | 2976 | attrs, |
michael@0 | 2977 | isDictionaryMember=self.dictionaryMember, |
michael@0 | 2978 | isOptional=self.optional) |
michael@0 | 2979 | for attribute in attrs: |
michael@0 | 2980 | identifier = attribute.identifier() |
michael@0 | 2981 | if identifier == "Clamp": |
michael@0 | 2982 | if not attribute.noArguments(): |
michael@0 | 2983 | raise WebIDLError("[Clamp] must take no arguments", |
michael@0 | 2984 | [attribute.location]) |
michael@0 | 2985 | if self.enforceRange: |
michael@0 | 2986 | raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", |
michael@0 | 2987 | [self.location]); |
michael@0 | 2988 | self.clamp = True |
michael@0 | 2989 | elif identifier == "EnforceRange": |
michael@0 | 2990 | if not attribute.noArguments(): |
michael@0 | 2991 | raise WebIDLError("[EnforceRange] must take no arguments", |
michael@0 | 2992 | [attribute.location]) |
michael@0 | 2993 | if self.clamp: |
michael@0 | 2994 | raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", |
michael@0 | 2995 | [self.location]); |
michael@0 | 2996 | self.enforceRange = True |
michael@0 | 2997 | elif identifier == "TreatNonCallableAsNull": |
michael@0 | 2998 | self._allowTreatNonCallableAsNull = True |
michael@0 | 2999 | else: |
michael@0 | 3000 | raise WebIDLError("Unhandled extended attribute on an argument", |
michael@0 | 3001 | [attribute.location]) |
michael@0 | 3002 | |
michael@0 | 3003 | def isComplete(self): |
michael@0 | 3004 | return self._isComplete |
michael@0 | 3005 | |
michael@0 | 3006 | def complete(self, scope): |
michael@0 | 3007 | if self._isComplete: |
michael@0 | 3008 | return |
michael@0 | 3009 | |
michael@0 | 3010 | self._isComplete = True |
michael@0 | 3011 | |
michael@0 | 3012 | if not self.type.isComplete(): |
michael@0 | 3013 | type = self.type.complete(scope) |
michael@0 | 3014 | assert not isinstance(type, IDLUnresolvedType) |
michael@0 | 3015 | assert not isinstance(type, IDLTypedefType) |
michael@0 | 3016 | assert not isinstance(type.name, IDLUnresolvedIdentifier) |
michael@0 | 3017 | self.type = type |
michael@0 | 3018 | |
michael@0 | 3019 | if ((self.type.isDictionary() or |
michael@0 | 3020 | self.type.isUnion() and self.type.unroll().hasDictionaryType) and |
michael@0 | 3021 | self.optional and not self.defaultValue): |
michael@0 | 3022 | # Default optional dictionaries to null, for simplicity, |
michael@0 | 3023 | # so the codegen doesn't have to special-case this. |
michael@0 | 3024 | self.defaultValue = IDLNullValue(self.location) |
michael@0 | 3025 | elif self.type.isAny(): |
michael@0 | 3026 | assert (self.defaultValue is None or |
michael@0 | 3027 | isinstance(self.defaultValue, IDLNullValue)) |
michael@0 | 3028 | # optional 'any' values always have a default value |
michael@0 | 3029 | if self.optional and not self.defaultValue and not self.variadic: |
michael@0 | 3030 | # Set the default value to undefined, for simplicity, so the |
michael@0 | 3031 | # codegen doesn't have to special-case this. |
michael@0 | 3032 | self.defaultValue = IDLUndefinedValue(self.location) |
michael@0 | 3033 | |
michael@0 | 3034 | # Now do the coercing thing; this needs to happen after the |
michael@0 | 3035 | # above creation of a default value. |
michael@0 | 3036 | if self.defaultValue: |
michael@0 | 3037 | self.defaultValue = self.defaultValue.coerceToType(self.type, |
michael@0 | 3038 | self.location) |
michael@0 | 3039 | assert self.defaultValue |
michael@0 | 3040 | |
michael@0 | 3041 | def allowTreatNonCallableAsNull(self): |
michael@0 | 3042 | return self._allowTreatNonCallableAsNull |
michael@0 | 3043 | |
michael@0 | 3044 | def _getDependentObjects(self): |
michael@0 | 3045 | deps = set([self.type]) |
michael@0 | 3046 | if self.defaultValue: |
michael@0 | 3047 | deps.add(self.defaultValue) |
michael@0 | 3048 | return deps |
michael@0 | 3049 | |
michael@0 | 3050 | class IDLCallbackType(IDLType, IDLObjectWithScope): |
michael@0 | 3051 | def __init__(self, location, parentScope, identifier, returnType, arguments): |
michael@0 | 3052 | assert isinstance(returnType, IDLType) |
michael@0 | 3053 | |
michael@0 | 3054 | IDLType.__init__(self, location, identifier.name) |
michael@0 | 3055 | |
michael@0 | 3056 | self._returnType = returnType |
michael@0 | 3057 | # Clone the list |
michael@0 | 3058 | self._arguments = list(arguments) |
michael@0 | 3059 | |
michael@0 | 3060 | IDLObjectWithScope.__init__(self, location, parentScope, identifier) |
michael@0 | 3061 | |
michael@0 | 3062 | for (returnType, arguments) in self.signatures(): |
michael@0 | 3063 | for argument in arguments: |
michael@0 | 3064 | argument.resolve(self) |
michael@0 | 3065 | |
michael@0 | 3066 | self._treatNonCallableAsNull = False |
michael@0 | 3067 | self._treatNonObjectAsNull = False |
michael@0 | 3068 | |
michael@0 | 3069 | def isCallback(self): |
michael@0 | 3070 | return True |
michael@0 | 3071 | |
michael@0 | 3072 | def signatures(self): |
michael@0 | 3073 | return [(self._returnType, self._arguments)] |
michael@0 | 3074 | |
michael@0 | 3075 | def tag(self): |
michael@0 | 3076 | return IDLType.Tags.callback |
michael@0 | 3077 | |
michael@0 | 3078 | def finish(self, scope): |
michael@0 | 3079 | if not self._returnType.isComplete(): |
michael@0 | 3080 | type = self._returnType.complete(scope) |
michael@0 | 3081 | |
michael@0 | 3082 | assert not isinstance(type, IDLUnresolvedType) |
michael@0 | 3083 | assert not isinstance(type, IDLTypedefType) |
michael@0 | 3084 | assert not isinstance(type.name, IDLUnresolvedIdentifier) |
michael@0 | 3085 | self._returnType = type |
michael@0 | 3086 | |
michael@0 | 3087 | for argument in self._arguments: |
michael@0 | 3088 | if argument.type.isComplete(): |
michael@0 | 3089 | continue |
michael@0 | 3090 | |
michael@0 | 3091 | type = argument.type.complete(scope) |
michael@0 | 3092 | |
michael@0 | 3093 | assert not isinstance(type, IDLUnresolvedType) |
michael@0 | 3094 | assert not isinstance(type, IDLTypedefType) |
michael@0 | 3095 | assert not isinstance(type.name, IDLUnresolvedIdentifier) |
michael@0 | 3096 | argument.type = type |
michael@0 | 3097 | |
michael@0 | 3098 | def validate(self): |
michael@0 | 3099 | pass |
michael@0 | 3100 | |
michael@0 | 3101 | def isDistinguishableFrom(self, other): |
michael@0 | 3102 | if other.isUnion(): |
michael@0 | 3103 | # Just forward to the union; it'll deal |
michael@0 | 3104 | return other.isDistinguishableFrom(self) |
michael@0 | 3105 | return (other.isPrimitive() or other.isString() or other.isEnum() or |
michael@0 | 3106 | other.isNonCallbackInterface() or other.isDate()) |
michael@0 | 3107 | |
michael@0 | 3108 | def addExtendedAttributes(self, attrs): |
michael@0 | 3109 | unhandledAttrs = [] |
michael@0 | 3110 | for attr in attrs: |
michael@0 | 3111 | if attr.identifier() == "TreatNonCallableAsNull": |
michael@0 | 3112 | self._treatNonCallableAsNull = True |
michael@0 | 3113 | elif attr.identifier() == "TreatNonObjectAsNull": |
michael@0 | 3114 | self._treatNonObjectAsNull = True |
michael@0 | 3115 | else: |
michael@0 | 3116 | unhandledAttrs.append(attr) |
michael@0 | 3117 | if self._treatNonCallableAsNull and self._treatNonObjectAsNull: |
michael@0 | 3118 | raise WebIDLError("Cannot specify both [TreatNonCallableAsNull] " |
michael@0 | 3119 | "and [TreatNonObjectAsNull]", [self.location]) |
michael@0 | 3120 | if len(unhandledAttrs) != 0: |
michael@0 | 3121 | IDLType.addExtendedAttributes(self, unhandledAttrs) |
michael@0 | 3122 | |
michael@0 | 3123 | def _getDependentObjects(self): |
michael@0 | 3124 | return set([self._returnType] + self._arguments) |
michael@0 | 3125 | |
michael@0 | 3126 | class IDLMethodOverload: |
michael@0 | 3127 | """ |
michael@0 | 3128 | A class that represents a single overload of a WebIDL method. This is not |
michael@0 | 3129 | quite the same as an element of the "effective overload set" in the spec, |
michael@0 | 3130 | because separate IDLMethodOverloads are not created based on arguments being |
michael@0 | 3131 | optional. Rather, when multiple methods have the same name, there is an |
michael@0 | 3132 | IDLMethodOverload for each one, all hanging off an IDLMethod representing |
michael@0 | 3133 | the full set of overloads. |
michael@0 | 3134 | """ |
michael@0 | 3135 | def __init__(self, returnType, arguments, location): |
michael@0 | 3136 | self.returnType = returnType |
michael@0 | 3137 | # Clone the list of arguments, just in case |
michael@0 | 3138 | self.arguments = list(arguments) |
michael@0 | 3139 | self.location = location |
michael@0 | 3140 | |
michael@0 | 3141 | def _getDependentObjects(self): |
michael@0 | 3142 | deps = set(self.arguments) |
michael@0 | 3143 | deps.add(self.returnType) |
michael@0 | 3144 | return deps |
michael@0 | 3145 | |
michael@0 | 3146 | class IDLMethod(IDLInterfaceMember, IDLScope): |
michael@0 | 3147 | |
michael@0 | 3148 | Special = enum( |
michael@0 | 3149 | 'Getter', |
michael@0 | 3150 | 'Setter', |
michael@0 | 3151 | 'Creator', |
michael@0 | 3152 | 'Deleter', |
michael@0 | 3153 | 'LegacyCaller', |
michael@0 | 3154 | base=IDLInterfaceMember.Special |
michael@0 | 3155 | ) |
michael@0 | 3156 | |
michael@0 | 3157 | TypeSuffixModifier = enum( |
michael@0 | 3158 | 'None', |
michael@0 | 3159 | 'QMark', |
michael@0 | 3160 | 'Brackets' |
michael@0 | 3161 | ) |
michael@0 | 3162 | |
michael@0 | 3163 | NamedOrIndexed = enum( |
michael@0 | 3164 | 'Neither', |
michael@0 | 3165 | 'Named', |
michael@0 | 3166 | 'Indexed' |
michael@0 | 3167 | ) |
michael@0 | 3168 | |
michael@0 | 3169 | def __init__(self, location, identifier, returnType, arguments, |
michael@0 | 3170 | static=False, getter=False, setter=False, creator=False, |
michael@0 | 3171 | deleter=False, specialType=NamedOrIndexed.Neither, |
michael@0 | 3172 | legacycaller=False, stringifier=False, jsonifier=False): |
michael@0 | 3173 | # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. |
michael@0 | 3174 | IDLInterfaceMember.__init__(self, location, identifier, |
michael@0 | 3175 | IDLInterfaceMember.Tags.Method) |
michael@0 | 3176 | |
michael@0 | 3177 | self._hasOverloads = False |
michael@0 | 3178 | |
michael@0 | 3179 | assert isinstance(returnType, IDLType) |
michael@0 | 3180 | |
michael@0 | 3181 | # self._overloads is a list of IDLMethodOverloads |
michael@0 | 3182 | self._overloads = [IDLMethodOverload(returnType, arguments, location)] |
michael@0 | 3183 | |
michael@0 | 3184 | assert isinstance(static, bool) |
michael@0 | 3185 | self._static = static |
michael@0 | 3186 | assert isinstance(getter, bool) |
michael@0 | 3187 | self._getter = getter |
michael@0 | 3188 | assert isinstance(setter, bool) |
michael@0 | 3189 | self._setter = setter |
michael@0 | 3190 | assert isinstance(creator, bool) |
michael@0 | 3191 | self._creator = creator |
michael@0 | 3192 | assert isinstance(deleter, bool) |
michael@0 | 3193 | self._deleter = deleter |
michael@0 | 3194 | assert isinstance(legacycaller, bool) |
michael@0 | 3195 | self._legacycaller = legacycaller |
michael@0 | 3196 | assert isinstance(stringifier, bool) |
michael@0 | 3197 | self._stringifier = stringifier |
michael@0 | 3198 | assert isinstance(jsonifier, bool) |
michael@0 | 3199 | self._jsonifier = jsonifier |
michael@0 | 3200 | self._specialType = specialType |
michael@0 | 3201 | |
michael@0 | 3202 | if static and identifier.name == "prototype": |
michael@0 | 3203 | raise WebIDLError("The identifier of a static operation must not be 'prototype'", |
michael@0 | 3204 | [location]) |
michael@0 | 3205 | |
michael@0 | 3206 | self.assertSignatureConstraints() |
michael@0 | 3207 | |
michael@0 | 3208 | def __str__(self): |
michael@0 | 3209 | return "Method '%s'" % self.identifier |
michael@0 | 3210 | |
michael@0 | 3211 | def assertSignatureConstraints(self): |
michael@0 | 3212 | if self._getter or self._deleter: |
michael@0 | 3213 | assert len(self._overloads) == 1 |
michael@0 | 3214 | overload = self._overloads[0] |
michael@0 | 3215 | arguments = overload.arguments |
michael@0 | 3216 | assert len(arguments) == 1 |
michael@0 | 3217 | assert arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] or \ |
michael@0 | 3218 | arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long] |
michael@0 | 3219 | assert not arguments[0].optional and not arguments[0].variadic |
michael@0 | 3220 | assert not self._getter or not overload.returnType.isVoid() |
michael@0 | 3221 | |
michael@0 | 3222 | if self._setter or self._creator: |
michael@0 | 3223 | assert len(self._overloads) == 1 |
michael@0 | 3224 | arguments = self._overloads[0].arguments |
michael@0 | 3225 | assert len(arguments) == 2 |
michael@0 | 3226 | assert arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] or \ |
michael@0 | 3227 | arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long] |
michael@0 | 3228 | assert not arguments[0].optional and not arguments[0].variadic |
michael@0 | 3229 | assert not arguments[1].optional and not arguments[1].variadic |
michael@0 | 3230 | |
michael@0 | 3231 | if self._stringifier: |
michael@0 | 3232 | assert len(self._overloads) == 1 |
michael@0 | 3233 | overload = self._overloads[0] |
michael@0 | 3234 | assert len(overload.arguments) == 0 |
michael@0 | 3235 | assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] |
michael@0 | 3236 | |
michael@0 | 3237 | if self._jsonifier: |
michael@0 | 3238 | assert len(self._overloads) == 1 |
michael@0 | 3239 | overload = self._overloads[0] |
michael@0 | 3240 | assert len(overload.arguments) == 0 |
michael@0 | 3241 | assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.object] |
michael@0 | 3242 | |
michael@0 | 3243 | def isStatic(self): |
michael@0 | 3244 | return self._static |
michael@0 | 3245 | |
michael@0 | 3246 | def isGetter(self): |
michael@0 | 3247 | return self._getter |
michael@0 | 3248 | |
michael@0 | 3249 | def isSetter(self): |
michael@0 | 3250 | return self._setter |
michael@0 | 3251 | |
michael@0 | 3252 | def isCreator(self): |
michael@0 | 3253 | return self._creator |
michael@0 | 3254 | |
michael@0 | 3255 | def isDeleter(self): |
michael@0 | 3256 | return self._deleter |
michael@0 | 3257 | |
michael@0 | 3258 | def isNamed(self): |
michael@0 | 3259 | assert self._specialType == IDLMethod.NamedOrIndexed.Named or \ |
michael@0 | 3260 | self._specialType == IDLMethod.NamedOrIndexed.Indexed |
michael@0 | 3261 | return self._specialType == IDLMethod.NamedOrIndexed.Named |
michael@0 | 3262 | |
michael@0 | 3263 | def isIndexed(self): |
michael@0 | 3264 | assert self._specialType == IDLMethod.NamedOrIndexed.Named or \ |
michael@0 | 3265 | self._specialType == IDLMethod.NamedOrIndexed.Indexed |
michael@0 | 3266 | return self._specialType == IDLMethod.NamedOrIndexed.Indexed |
michael@0 | 3267 | |
michael@0 | 3268 | def isLegacycaller(self): |
michael@0 | 3269 | return self._legacycaller |
michael@0 | 3270 | |
michael@0 | 3271 | def isStringifier(self): |
michael@0 | 3272 | return self._stringifier |
michael@0 | 3273 | |
michael@0 | 3274 | def isJsonifier(self): |
michael@0 | 3275 | return self._jsonifier |
michael@0 | 3276 | |
michael@0 | 3277 | def hasOverloads(self): |
michael@0 | 3278 | return self._hasOverloads |
michael@0 | 3279 | |
michael@0 | 3280 | def isIdentifierLess(self): |
michael@0 | 3281 | return self.identifier.name[:2] == "__" and self.identifier.name != "__noSuchMethod__" |
michael@0 | 3282 | |
michael@0 | 3283 | def resolve(self, parentScope): |
michael@0 | 3284 | assert isinstance(parentScope, IDLScope) |
michael@0 | 3285 | IDLObjectWithIdentifier.resolve(self, parentScope) |
michael@0 | 3286 | IDLScope.__init__(self, self.location, parentScope, self.identifier) |
michael@0 | 3287 | for (returnType, arguments) in self.signatures(): |
michael@0 | 3288 | for argument in arguments: |
michael@0 | 3289 | argument.resolve(self) |
michael@0 | 3290 | |
michael@0 | 3291 | def addOverload(self, method): |
michael@0 | 3292 | assert len(method._overloads) == 1 |
michael@0 | 3293 | |
michael@0 | 3294 | if self._extendedAttrDict != method ._extendedAttrDict: |
michael@0 | 3295 | raise WebIDLError("Extended attributes differ on different " |
michael@0 | 3296 | "overloads of %s" % method.identifier, |
michael@0 | 3297 | [self.location, method.location]) |
michael@0 | 3298 | |
michael@0 | 3299 | self._overloads.extend(method._overloads) |
michael@0 | 3300 | |
michael@0 | 3301 | self._hasOverloads = True |
michael@0 | 3302 | |
michael@0 | 3303 | if self.isStatic() != method.isStatic(): |
michael@0 | 3304 | raise WebIDLError("Overloaded identifier %s appears with different values of the 'static' attribute" % method.identifier, |
michael@0 | 3305 | [method.location]) |
michael@0 | 3306 | |
michael@0 | 3307 | if self.isLegacycaller() != method.isLegacycaller(): |
michael@0 | 3308 | raise WebIDLError("Overloaded identifier %s appears with different values of the 'legacycaller' attribute" % method.identifier, |
michael@0 | 3309 | [method.location]) |
michael@0 | 3310 | |
michael@0 | 3311 | # Can't overload special things! |
michael@0 | 3312 | assert not self.isGetter() |
michael@0 | 3313 | assert not method.isGetter() |
michael@0 | 3314 | assert not self.isSetter() |
michael@0 | 3315 | assert not method.isSetter() |
michael@0 | 3316 | assert not self.isCreator() |
michael@0 | 3317 | assert not method.isCreator() |
michael@0 | 3318 | assert not self.isDeleter() |
michael@0 | 3319 | assert not method.isDeleter() |
michael@0 | 3320 | assert not self.isStringifier() |
michael@0 | 3321 | assert not method.isStringifier() |
michael@0 | 3322 | assert not self.isJsonifier() |
michael@0 | 3323 | assert not method.isJsonifier() |
michael@0 | 3324 | |
michael@0 | 3325 | return self |
michael@0 | 3326 | |
michael@0 | 3327 | def signatures(self): |
michael@0 | 3328 | return [(overload.returnType, overload.arguments) for overload in |
michael@0 | 3329 | self._overloads] |
michael@0 | 3330 | |
michael@0 | 3331 | def finish(self, scope): |
michael@0 | 3332 | overloadWithPromiseReturnType = None |
michael@0 | 3333 | overloadWithoutPromiseReturnType = None |
michael@0 | 3334 | for overload in self._overloads: |
michael@0 | 3335 | variadicArgument = None |
michael@0 | 3336 | |
michael@0 | 3337 | arguments = overload.arguments |
michael@0 | 3338 | for (idx, argument) in enumerate(arguments): |
michael@0 | 3339 | if not argument.isComplete(): |
michael@0 | 3340 | argument.complete(scope) |
michael@0 | 3341 | assert argument.type.isComplete() |
michael@0 | 3342 | |
michael@0 | 3343 | if (argument.type.isDictionary() or |
michael@0 | 3344 | (argument.type.isUnion() and |
michael@0 | 3345 | argument.type.unroll().hasDictionaryType)): |
michael@0 | 3346 | # Dictionaries and unions containing dictionaries at the |
michael@0 | 3347 | # end of the list or followed by optional arguments must be |
michael@0 | 3348 | # optional. |
michael@0 | 3349 | if (not argument.optional and |
michael@0 | 3350 | all(arg.optional for arg in arguments[idx+1:])): |
michael@0 | 3351 | raise WebIDLError("Dictionary argument or union " |
michael@0 | 3352 | "argument containing a dictionary " |
michael@0 | 3353 | "not followed by a required argument " |
michael@0 | 3354 | "must be optional", |
michael@0 | 3355 | [argument.location]) |
michael@0 | 3356 | |
michael@0 | 3357 | # An argument cannot be a Nullable Dictionary |
michael@0 | 3358 | if argument.type.nullable(): |
michael@0 | 3359 | raise WebIDLError("An argument cannot be a nullable " |
michael@0 | 3360 | "dictionary or nullable union " |
michael@0 | 3361 | "containing a dictionary", |
michael@0 | 3362 | [argument.location]) |
michael@0 | 3363 | |
michael@0 | 3364 | # Only the last argument can be variadic |
michael@0 | 3365 | if variadicArgument: |
michael@0 | 3366 | raise WebIDLError("Variadic argument is not last argument", |
michael@0 | 3367 | [variadicArgument.location]) |
michael@0 | 3368 | if argument.variadic: |
michael@0 | 3369 | variadicArgument = argument |
michael@0 | 3370 | |
michael@0 | 3371 | returnType = overload.returnType |
michael@0 | 3372 | if not returnType.isComplete(): |
michael@0 | 3373 | returnType = returnType.complete(scope) |
michael@0 | 3374 | assert not isinstance(returnType, IDLUnresolvedType) |
michael@0 | 3375 | assert not isinstance(returnType, IDLTypedefType) |
michael@0 | 3376 | assert not isinstance(returnType.name, IDLUnresolvedIdentifier) |
michael@0 | 3377 | overload.returnType = returnType |
michael@0 | 3378 | |
michael@0 | 3379 | if returnType.isPromise(): |
michael@0 | 3380 | overloadWithPromiseReturnType = overload |
michael@0 | 3381 | else: |
michael@0 | 3382 | overloadWithoutPromiseReturnType = overload |
michael@0 | 3383 | |
michael@0 | 3384 | # Make sure either all our overloads return Promises or none do |
michael@0 | 3385 | if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType: |
michael@0 | 3386 | raise WebIDLError("We have overloads with both Promise and " |
michael@0 | 3387 | "non-Promise return types", |
michael@0 | 3388 | [overloadWithPromiseReturnType.location, |
michael@0 | 3389 | overloadWithoutPromiseReturnType.location]) |
michael@0 | 3390 | |
michael@0 | 3391 | if overloadWithPromiseReturnType and self._legacycaller: |
michael@0 | 3392 | raise WebIDLError("May not have a Promise return type for a " |
michael@0 | 3393 | "legacycaller.", |
michael@0 | 3394 | [overloadWithPromiseReturnType.location]) |
michael@0 | 3395 | |
michael@0 | 3396 | # Now compute various information that will be used by the |
michael@0 | 3397 | # WebIDL overload resolution algorithm. |
michael@0 | 3398 | self.maxArgCount = max(len(s[1]) for s in self.signatures()) |
michael@0 | 3399 | self.allowedArgCounts = [ i for i in range(self.maxArgCount+1) |
michael@0 | 3400 | if len(self.signaturesForArgCount(i)) != 0 ] |
michael@0 | 3401 | |
michael@0 | 3402 | def validate(self): |
michael@0 | 3403 | # Make sure our overloads are properly distinguishable and don't have |
michael@0 | 3404 | # different argument types before the distinguishing args. |
michael@0 | 3405 | for argCount in self.allowedArgCounts: |
michael@0 | 3406 | possibleOverloads = self.overloadsForArgCount(argCount) |
michael@0 | 3407 | if len(possibleOverloads) == 1: |
michael@0 | 3408 | continue |
michael@0 | 3409 | distinguishingIndex = self.distinguishingIndexForArgCount(argCount) |
michael@0 | 3410 | for idx in range(distinguishingIndex): |
michael@0 | 3411 | firstSigType = possibleOverloads[0].arguments[idx].type |
michael@0 | 3412 | for overload in possibleOverloads[1:]: |
michael@0 | 3413 | if overload.arguments[idx].type != firstSigType: |
michael@0 | 3414 | raise WebIDLError( |
michael@0 | 3415 | "Signatures for method '%s' with %d arguments have " |
michael@0 | 3416 | "different types of arguments at index %d, which " |
michael@0 | 3417 | "is before distinguishing index %d" % |
michael@0 | 3418 | (self.identifier.name, argCount, idx, |
michael@0 | 3419 | distinguishingIndex), |
michael@0 | 3420 | [self.location, overload.location]) |
michael@0 | 3421 | |
michael@0 | 3422 | def overloadsForArgCount(self, argc): |
michael@0 | 3423 | return [overload for overload in self._overloads if |
michael@0 | 3424 | len(overload.arguments) == argc or |
michael@0 | 3425 | (len(overload.arguments) > argc and |
michael@0 | 3426 | all(arg.optional for arg in overload.arguments[argc:])) or |
michael@0 | 3427 | (len(overload.arguments) < argc and |
michael@0 | 3428 | len(overload.arguments) > 0 and |
michael@0 | 3429 | overload.arguments[-1].variadic)] |
michael@0 | 3430 | |
michael@0 | 3431 | def signaturesForArgCount(self, argc): |
michael@0 | 3432 | return [(overload.returnType, overload.arguments) for overload |
michael@0 | 3433 | in self.overloadsForArgCount(argc)] |
michael@0 | 3434 | |
michael@0 | 3435 | def locationsForArgCount(self, argc): |
michael@0 | 3436 | return [overload.location for overload in self.overloadsForArgCount(argc)] |
michael@0 | 3437 | |
michael@0 | 3438 | def distinguishingIndexForArgCount(self, argc): |
michael@0 | 3439 | def isValidDistinguishingIndex(idx, signatures): |
michael@0 | 3440 | for (firstSigIndex, (firstRetval, firstArgs)) in enumerate(signatures[:-1]): |
michael@0 | 3441 | for (secondRetval, secondArgs) in signatures[firstSigIndex+1:]: |
michael@0 | 3442 | if idx < len(firstArgs): |
michael@0 | 3443 | firstType = firstArgs[idx].type |
michael@0 | 3444 | else: |
michael@0 | 3445 | assert(firstArgs[-1].variadic) |
michael@0 | 3446 | firstType = firstArgs[-1].type |
michael@0 | 3447 | if idx < len(secondArgs): |
michael@0 | 3448 | secondType = secondArgs[idx].type |
michael@0 | 3449 | else: |
michael@0 | 3450 | assert(secondArgs[-1].variadic) |
michael@0 | 3451 | secondType = secondArgs[-1].type |
michael@0 | 3452 | if not firstType.isDistinguishableFrom(secondType): |
michael@0 | 3453 | return False |
michael@0 | 3454 | return True |
michael@0 | 3455 | signatures = self.signaturesForArgCount(argc) |
michael@0 | 3456 | for idx in range(argc): |
michael@0 | 3457 | if isValidDistinguishingIndex(idx, signatures): |
michael@0 | 3458 | return idx |
michael@0 | 3459 | # No valid distinguishing index. Time to throw |
michael@0 | 3460 | locations = self.locationsForArgCount(argc) |
michael@0 | 3461 | raise WebIDLError("Signatures with %d arguments for method '%s' are not " |
michael@0 | 3462 | "distinguishable" % (argc, self.identifier.name), |
michael@0 | 3463 | locations) |
michael@0 | 3464 | |
michael@0 | 3465 | def handleExtendedAttribute(self, attr): |
michael@0 | 3466 | identifier = attr.identifier() |
michael@0 | 3467 | if identifier == "GetterThrows": |
michael@0 | 3468 | raise WebIDLError("Methods must not be flagged as " |
michael@0 | 3469 | "[GetterThrows]", |
michael@0 | 3470 | [attr.location, self.location]) |
michael@0 | 3471 | elif identifier == "SetterThrows": |
michael@0 | 3472 | raise WebIDLError("Methods must not be flagged as " |
michael@0 | 3473 | "[SetterThrows]", |
michael@0 | 3474 | [attr.location, self.location]) |
michael@0 | 3475 | elif identifier == "Unforgeable": |
michael@0 | 3476 | raise WebIDLError("Methods must not be flagged as " |
michael@0 | 3477 | "[Unforgeable]", |
michael@0 | 3478 | [attr.location, self.location]) |
michael@0 | 3479 | elif identifier == "SameObject": |
michael@0 | 3480 | raise WebIDLError("Methods must not be flagged as [SameObject]", |
michael@0 | 3481 | [attr.location, self.location]); |
michael@0 | 3482 | elif identifier == "Constant": |
michael@0 | 3483 | raise WebIDLError("Methods must not be flagged as [Constant]", |
michael@0 | 3484 | [attr.location, self.location]); |
michael@0 | 3485 | elif identifier == "PutForwards": |
michael@0 | 3486 | raise WebIDLError("Only attributes support [PutForwards]", |
michael@0 | 3487 | [attr.location, self.location]) |
michael@0 | 3488 | elif identifier == "LenientFloat": |
michael@0 | 3489 | # This is called before we've done overload resolution |
michael@0 | 3490 | assert len(self.signatures()) == 1 |
michael@0 | 3491 | sig = self.signatures()[0] |
michael@0 | 3492 | if not sig[0].isVoid(): |
michael@0 | 3493 | raise WebIDLError("[LenientFloat] used on a non-void method", |
michael@0 | 3494 | [attr.location, self.location]) |
michael@0 | 3495 | if not any(arg.type.includesRestrictedFloat() for arg in sig[1]): |
michael@0 | 3496 | raise WebIDLError("[LenientFloat] used on an operation with no " |
michael@0 | 3497 | "restricted float type arguments", |
michael@0 | 3498 | [attr.location, self.location]) |
michael@0 | 3499 | elif (identifier == "Throws" or |
michael@0 | 3500 | identifier == "NewObject" or |
michael@0 | 3501 | identifier == "ChromeOnly" or |
michael@0 | 3502 | identifier == "Pref" or |
michael@0 | 3503 | identifier == "Func" or |
michael@0 | 3504 | identifier == "AvailableIn" or |
michael@0 | 3505 | identifier == "Pure" or |
michael@0 | 3506 | identifier == "CrossOriginCallable" or |
michael@0 | 3507 | identifier == "WebGLHandlesContextLoss"): |
michael@0 | 3508 | # Known attributes that we don't need to do anything with here |
michael@0 | 3509 | pass |
michael@0 | 3510 | else: |
michael@0 | 3511 | raise WebIDLError("Unknown extended attribute %s on method" % identifier, |
michael@0 | 3512 | [attr.location]) |
michael@0 | 3513 | IDLInterfaceMember.handleExtendedAttribute(self, attr) |
michael@0 | 3514 | |
michael@0 | 3515 | def returnsPromise(self): |
michael@0 | 3516 | return self._overloads[0].returnType.isPromise() |
michael@0 | 3517 | |
michael@0 | 3518 | def _getDependentObjects(self): |
michael@0 | 3519 | deps = set() |
michael@0 | 3520 | for overload in self._overloads: |
michael@0 | 3521 | deps.union(overload._getDependentObjects()) |
michael@0 | 3522 | return deps |
michael@0 | 3523 | |
michael@0 | 3524 | class IDLImplementsStatement(IDLObject): |
michael@0 | 3525 | def __init__(self, location, implementor, implementee): |
michael@0 | 3526 | IDLObject.__init__(self, location) |
michael@0 | 3527 | self.implementor = implementor; |
michael@0 | 3528 | self.implementee = implementee |
michael@0 | 3529 | |
michael@0 | 3530 | def finish(self, scope): |
michael@0 | 3531 | assert(isinstance(self.implementor, IDLIdentifierPlaceholder)) |
michael@0 | 3532 | assert(isinstance(self.implementee, IDLIdentifierPlaceholder)) |
michael@0 | 3533 | implementor = self.implementor.finish(scope) |
michael@0 | 3534 | implementee = self.implementee.finish(scope) |
michael@0 | 3535 | # NOTE: we depend on not setting self.implementor and |
michael@0 | 3536 | # self.implementee here to keep track of the original |
michael@0 | 3537 | # locations. |
michael@0 | 3538 | if not isinstance(implementor, IDLInterface): |
michael@0 | 3539 | raise WebIDLError("Left-hand side of 'implements' is not an " |
michael@0 | 3540 | "interface", |
michael@0 | 3541 | [self.implementor.location]) |
michael@0 | 3542 | if implementor.isCallback(): |
michael@0 | 3543 | raise WebIDLError("Left-hand side of 'implements' is a callback " |
michael@0 | 3544 | "interface", |
michael@0 | 3545 | [self.implementor.location]) |
michael@0 | 3546 | if not isinstance(implementee, IDLInterface): |
michael@0 | 3547 | raise WebIDLError("Right-hand side of 'implements' is not an " |
michael@0 | 3548 | "interface", |
michael@0 | 3549 | [self.implementee.location]) |
michael@0 | 3550 | if implementee.isCallback(): |
michael@0 | 3551 | raise WebIDLError("Right-hand side of 'implements' is a callback " |
michael@0 | 3552 | "interface", |
michael@0 | 3553 | [self.implementee.location]) |
michael@0 | 3554 | implementor.addImplementedInterface(implementee) |
michael@0 | 3555 | |
michael@0 | 3556 | def validate(self): |
michael@0 | 3557 | pass |
michael@0 | 3558 | |
michael@0 | 3559 | def addExtendedAttributes(self, attrs): |
michael@0 | 3560 | assert len(attrs) == 0 |
michael@0 | 3561 | |
michael@0 | 3562 | class IDLExtendedAttribute(IDLObject): |
michael@0 | 3563 | """ |
michael@0 | 3564 | A class to represent IDL extended attributes so we can give them locations |
michael@0 | 3565 | """ |
michael@0 | 3566 | def __init__(self, location, tuple): |
michael@0 | 3567 | IDLObject.__init__(self, location) |
michael@0 | 3568 | self._tuple = tuple |
michael@0 | 3569 | |
michael@0 | 3570 | def identifier(self): |
michael@0 | 3571 | return self._tuple[0] |
michael@0 | 3572 | |
michael@0 | 3573 | def noArguments(self): |
michael@0 | 3574 | return len(self._tuple) == 1 |
michael@0 | 3575 | |
michael@0 | 3576 | def hasValue(self): |
michael@0 | 3577 | return len(self._tuple) >= 2 and isinstance(self._tuple[1], str) |
michael@0 | 3578 | |
michael@0 | 3579 | def value(self): |
michael@0 | 3580 | assert(self.hasValue()) |
michael@0 | 3581 | return self._tuple[1] |
michael@0 | 3582 | |
michael@0 | 3583 | def hasArgs(self): |
michael@0 | 3584 | return (len(self._tuple) == 2 and isinstance(self._tuple[1], list) or |
michael@0 | 3585 | len(self._tuple) == 3) |
michael@0 | 3586 | |
michael@0 | 3587 | def args(self): |
michael@0 | 3588 | assert(self.hasArgs()) |
michael@0 | 3589 | # Our args are our last element |
michael@0 | 3590 | return self._tuple[-1] |
michael@0 | 3591 | |
michael@0 | 3592 | def listValue(self): |
michael@0 | 3593 | """ |
michael@0 | 3594 | Backdoor for storing random data in _extendedAttrDict |
michael@0 | 3595 | """ |
michael@0 | 3596 | return list(self._tuple)[1:] |
michael@0 | 3597 | |
michael@0 | 3598 | # Parser |
michael@0 | 3599 | |
michael@0 | 3600 | class Tokenizer(object): |
michael@0 | 3601 | tokens = [ |
michael@0 | 3602 | "INTEGER", |
michael@0 | 3603 | "FLOATLITERAL", |
michael@0 | 3604 | "IDENTIFIER", |
michael@0 | 3605 | "STRING", |
michael@0 | 3606 | "WHITESPACE", |
michael@0 | 3607 | "OTHER" |
michael@0 | 3608 | ] |
michael@0 | 3609 | |
michael@0 | 3610 | def t_FLOATLITERAL(self, t): |
michael@0 | 3611 | r'(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+|Infinity))|NaN' |
michael@0 | 3612 | t.value = float(t.value) |
michael@0 | 3613 | return t |
michael@0 | 3614 | |
michael@0 | 3615 | def t_INTEGER(self, t): |
michael@0 | 3616 | r'-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)' |
michael@0 | 3617 | try: |
michael@0 | 3618 | # Can't use int(), because that doesn't handle octal properly. |
michael@0 | 3619 | t.value = parseInt(t.value) |
michael@0 | 3620 | except: |
michael@0 | 3621 | raise WebIDLError("Invalid integer literal", |
michael@0 | 3622 | [Location(lexer=self.lexer, |
michael@0 | 3623 | lineno=self.lexer.lineno, |
michael@0 | 3624 | lexpos=self.lexer.lexpos, |
michael@0 | 3625 | filename=self._filename)]) |
michael@0 | 3626 | return t |
michael@0 | 3627 | |
michael@0 | 3628 | def t_IDENTIFIER(self, t): |
michael@0 | 3629 | r'[A-Z_a-z][0-9A-Z_a-z]*' |
michael@0 | 3630 | t.type = self.keywords.get(t.value, 'IDENTIFIER') |
michael@0 | 3631 | return t |
michael@0 | 3632 | |
michael@0 | 3633 | def t_STRING(self, t): |
michael@0 | 3634 | r'"[^"]*"' |
michael@0 | 3635 | t.value = t.value[1:-1] |
michael@0 | 3636 | return t |
michael@0 | 3637 | |
michael@0 | 3638 | def t_WHITESPACE(self, t): |
michael@0 | 3639 | r'[\t\n\r ]+|[\t\n\r ]*((//[^\n]*|/\*.*?\*/)[\t\n\r ]*)+' |
michael@0 | 3640 | pass |
michael@0 | 3641 | |
michael@0 | 3642 | def t_ELLIPSIS(self, t): |
michael@0 | 3643 | r'\.\.\.' |
michael@0 | 3644 | t.type = self.keywords.get(t.value) |
michael@0 | 3645 | return t |
michael@0 | 3646 | |
michael@0 | 3647 | def t_OTHER(self, t): |
michael@0 | 3648 | r'[^\t\n\r 0-9A-Z_a-z]' |
michael@0 | 3649 | t.type = self.keywords.get(t.value, 'OTHER') |
michael@0 | 3650 | return t |
michael@0 | 3651 | |
michael@0 | 3652 | keywords = { |
michael@0 | 3653 | "module": "MODULE", |
michael@0 | 3654 | "interface": "INTERFACE", |
michael@0 | 3655 | "partial": "PARTIAL", |
michael@0 | 3656 | "dictionary": "DICTIONARY", |
michael@0 | 3657 | "exception": "EXCEPTION", |
michael@0 | 3658 | "enum": "ENUM", |
michael@0 | 3659 | "callback": "CALLBACK", |
michael@0 | 3660 | "typedef": "TYPEDEF", |
michael@0 | 3661 | "implements": "IMPLEMENTS", |
michael@0 | 3662 | "const": "CONST", |
michael@0 | 3663 | "null": "NULL", |
michael@0 | 3664 | "true": "TRUE", |
michael@0 | 3665 | "false": "FALSE", |
michael@0 | 3666 | "serializer": "SERIALIZER", |
michael@0 | 3667 | "stringifier": "STRINGIFIER", |
michael@0 | 3668 | "jsonifier": "JSONIFIER", |
michael@0 | 3669 | "unrestricted": "UNRESTRICTED", |
michael@0 | 3670 | "attribute": "ATTRIBUTE", |
michael@0 | 3671 | "readonly": "READONLY", |
michael@0 | 3672 | "inherit": "INHERIT", |
michael@0 | 3673 | "static": "STATIC", |
michael@0 | 3674 | "getter": "GETTER", |
michael@0 | 3675 | "setter": "SETTER", |
michael@0 | 3676 | "creator": "CREATOR", |
michael@0 | 3677 | "deleter": "DELETER", |
michael@0 | 3678 | "legacycaller": "LEGACYCALLER", |
michael@0 | 3679 | "optional": "OPTIONAL", |
michael@0 | 3680 | "...": "ELLIPSIS", |
michael@0 | 3681 | "::": "SCOPE", |
michael@0 | 3682 | "Date": "DATE", |
michael@0 | 3683 | "DOMString": "DOMSTRING", |
michael@0 | 3684 | "ByteString": "BYTESTRING", |
michael@0 | 3685 | "any": "ANY", |
michael@0 | 3686 | "boolean": "BOOLEAN", |
michael@0 | 3687 | "byte": "BYTE", |
michael@0 | 3688 | "double": "DOUBLE", |
michael@0 | 3689 | "float": "FLOAT", |
michael@0 | 3690 | "long": "LONG", |
michael@0 | 3691 | "object": "OBJECT", |
michael@0 | 3692 | "octet": "OCTET", |
michael@0 | 3693 | "optional": "OPTIONAL", |
michael@0 | 3694 | "sequence": "SEQUENCE", |
michael@0 | 3695 | "MozMap": "MOZMAP", |
michael@0 | 3696 | "short": "SHORT", |
michael@0 | 3697 | "unsigned": "UNSIGNED", |
michael@0 | 3698 | "void": "VOID", |
michael@0 | 3699 | ":": "COLON", |
michael@0 | 3700 | ";": "SEMICOLON", |
michael@0 | 3701 | "{": "LBRACE", |
michael@0 | 3702 | "}": "RBRACE", |
michael@0 | 3703 | "(": "LPAREN", |
michael@0 | 3704 | ")": "RPAREN", |
michael@0 | 3705 | "[": "LBRACKET", |
michael@0 | 3706 | "]": "RBRACKET", |
michael@0 | 3707 | "?": "QUESTIONMARK", |
michael@0 | 3708 | ",": "COMMA", |
michael@0 | 3709 | "=": "EQUALS", |
michael@0 | 3710 | "<": "LT", |
michael@0 | 3711 | ">": "GT", |
michael@0 | 3712 | "ArrayBuffer": "ARRAYBUFFER", |
michael@0 | 3713 | "or": "OR" |
michael@0 | 3714 | } |
michael@0 | 3715 | |
michael@0 | 3716 | tokens.extend(keywords.values()) |
michael@0 | 3717 | |
michael@0 | 3718 | def t_error(self, t): |
michael@0 | 3719 | raise WebIDLError("Unrecognized Input", |
michael@0 | 3720 | [Location(lexer=self.lexer, |
michael@0 | 3721 | lineno=self.lexer.lineno, |
michael@0 | 3722 | lexpos=self.lexer.lexpos, |
michael@0 | 3723 | filename = self.filename)]) |
michael@0 | 3724 | |
michael@0 | 3725 | def __init__(self, outputdir, lexer=None): |
michael@0 | 3726 | if lexer: |
michael@0 | 3727 | self.lexer = lexer |
michael@0 | 3728 | else: |
michael@0 | 3729 | self.lexer = lex.lex(object=self, |
michael@0 | 3730 | outputdir=outputdir, |
michael@0 | 3731 | lextab='webidllex', |
michael@0 | 3732 | reflags=re.DOTALL) |
michael@0 | 3733 | |
michael@0 | 3734 | class Parser(Tokenizer): |
michael@0 | 3735 | def getLocation(self, p, i): |
michael@0 | 3736 | return Location(self.lexer, p.lineno(i), p.lexpos(i), self._filename) |
michael@0 | 3737 | |
michael@0 | 3738 | def globalScope(self): |
michael@0 | 3739 | return self._globalScope |
michael@0 | 3740 | |
michael@0 | 3741 | # The p_Foo functions here must match the WebIDL spec's grammar. |
michael@0 | 3742 | # It's acceptable to split things at '|' boundaries. |
michael@0 | 3743 | def p_Definitions(self, p): |
michael@0 | 3744 | """ |
michael@0 | 3745 | Definitions : ExtendedAttributeList Definition Definitions |
michael@0 | 3746 | """ |
michael@0 | 3747 | if p[2]: |
michael@0 | 3748 | p[0] = [p[2]] |
michael@0 | 3749 | p[2].addExtendedAttributes(p[1]) |
michael@0 | 3750 | else: |
michael@0 | 3751 | assert not p[1] |
michael@0 | 3752 | p[0] = [] |
michael@0 | 3753 | |
michael@0 | 3754 | p[0].extend(p[3]) |
michael@0 | 3755 | |
michael@0 | 3756 | def p_DefinitionsEmpty(self, p): |
michael@0 | 3757 | """ |
michael@0 | 3758 | Definitions : |
michael@0 | 3759 | """ |
michael@0 | 3760 | p[0] = [] |
michael@0 | 3761 | |
michael@0 | 3762 | def p_Definition(self, p): |
michael@0 | 3763 | """ |
michael@0 | 3764 | Definition : CallbackOrInterface |
michael@0 | 3765 | | PartialInterface |
michael@0 | 3766 | | Dictionary |
michael@0 | 3767 | | Exception |
michael@0 | 3768 | | Enum |
michael@0 | 3769 | | Typedef |
michael@0 | 3770 | | ImplementsStatement |
michael@0 | 3771 | """ |
michael@0 | 3772 | p[0] = p[1] |
michael@0 | 3773 | assert p[1] # We might not have implemented something ... |
michael@0 | 3774 | |
michael@0 | 3775 | def p_CallbackOrInterfaceCallback(self, p): |
michael@0 | 3776 | """ |
michael@0 | 3777 | CallbackOrInterface : CALLBACK CallbackRestOrInterface |
michael@0 | 3778 | """ |
michael@0 | 3779 | if p[2].isInterface(): |
michael@0 | 3780 | assert isinstance(p[2], IDLInterface) |
michael@0 | 3781 | p[2].setCallback(True) |
michael@0 | 3782 | |
michael@0 | 3783 | p[0] = p[2] |
michael@0 | 3784 | |
michael@0 | 3785 | def p_CallbackOrInterfaceInterface(self, p): |
michael@0 | 3786 | """ |
michael@0 | 3787 | CallbackOrInterface : Interface |
michael@0 | 3788 | """ |
michael@0 | 3789 | p[0] = p[1] |
michael@0 | 3790 | |
michael@0 | 3791 | def p_CallbackRestOrInterface(self, p): |
michael@0 | 3792 | """ |
michael@0 | 3793 | CallbackRestOrInterface : CallbackRest |
michael@0 | 3794 | | Interface |
michael@0 | 3795 | """ |
michael@0 | 3796 | assert p[1] |
michael@0 | 3797 | p[0] = p[1] |
michael@0 | 3798 | |
michael@0 | 3799 | def p_Interface(self, p): |
michael@0 | 3800 | """ |
michael@0 | 3801 | Interface : INTERFACE IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON |
michael@0 | 3802 | """ |
michael@0 | 3803 | location = self.getLocation(p, 1) |
michael@0 | 3804 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) |
michael@0 | 3805 | members = p[5] |
michael@0 | 3806 | parent = p[3] |
michael@0 | 3807 | |
michael@0 | 3808 | try: |
michael@0 | 3809 | if self.globalScope()._lookupIdentifier(identifier): |
michael@0 | 3810 | p[0] = self.globalScope()._lookupIdentifier(identifier) |
michael@0 | 3811 | if not isinstance(p[0], IDLInterface): |
michael@0 | 3812 | raise WebIDLError("Partial interface has the same name as " |
michael@0 | 3813 | "non-interface object", |
michael@0 | 3814 | [location, p[0].location]) |
michael@0 | 3815 | p[0].setNonPartial(location, parent, members) |
michael@0 | 3816 | return |
michael@0 | 3817 | except Exception, ex: |
michael@0 | 3818 | if isinstance(ex, WebIDLError): |
michael@0 | 3819 | raise ex |
michael@0 | 3820 | pass |
michael@0 | 3821 | |
michael@0 | 3822 | p[0] = IDLInterface(location, self.globalScope(), identifier, parent, |
michael@0 | 3823 | members, isPartial=False) |
michael@0 | 3824 | |
michael@0 | 3825 | def p_InterfaceForwardDecl(self, p): |
michael@0 | 3826 | """ |
michael@0 | 3827 | Interface : INTERFACE IDENTIFIER SEMICOLON |
michael@0 | 3828 | """ |
michael@0 | 3829 | location = self.getLocation(p, 1) |
michael@0 | 3830 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) |
michael@0 | 3831 | |
michael@0 | 3832 | try: |
michael@0 | 3833 | if self.globalScope()._lookupIdentifier(identifier): |
michael@0 | 3834 | p[0] = self.globalScope()._lookupIdentifier(identifier) |
michael@0 | 3835 | if not isinstance(p[0], IDLExternalInterface): |
michael@0 | 3836 | raise WebIDLError("Name collision between external " |
michael@0 | 3837 | "interface declaration for identifier " |
michael@0 | 3838 | "%s and %s" % (identifier.name, p[0]), |
michael@0 | 3839 | [location, p[0].location]) |
michael@0 | 3840 | return |
michael@0 | 3841 | except Exception, ex: |
michael@0 | 3842 | if isinstance(ex, WebIDLError): |
michael@0 | 3843 | raise ex |
michael@0 | 3844 | pass |
michael@0 | 3845 | |
michael@0 | 3846 | p[0] = IDLExternalInterface(location, self.globalScope(), identifier) |
michael@0 | 3847 | |
michael@0 | 3848 | def p_PartialInterface(self, p): |
michael@0 | 3849 | """ |
michael@0 | 3850 | PartialInterface : PARTIAL INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON |
michael@0 | 3851 | """ |
michael@0 | 3852 | location = self.getLocation(p, 2) |
michael@0 | 3853 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) |
michael@0 | 3854 | members = p[5] |
michael@0 | 3855 | |
michael@0 | 3856 | try: |
michael@0 | 3857 | if self.globalScope()._lookupIdentifier(identifier): |
michael@0 | 3858 | p[0] = self.globalScope()._lookupIdentifier(identifier) |
michael@0 | 3859 | if not isinstance(p[0], IDLInterface): |
michael@0 | 3860 | raise WebIDLError("Partial interface has the same name as " |
michael@0 | 3861 | "non-interface object", |
michael@0 | 3862 | [location, p[0].location]) |
michael@0 | 3863 | # Just throw our members into the existing IDLInterface. If we |
michael@0 | 3864 | # have extended attributes, those will get added to it |
michael@0 | 3865 | # automatically. |
michael@0 | 3866 | p[0].members.extend(members) |
michael@0 | 3867 | return |
michael@0 | 3868 | except Exception, ex: |
michael@0 | 3869 | if isinstance(ex, WebIDLError): |
michael@0 | 3870 | raise ex |
michael@0 | 3871 | pass |
michael@0 | 3872 | |
michael@0 | 3873 | p[0] = IDLInterface(location, self.globalScope(), identifier, None, |
michael@0 | 3874 | members, isPartial=True) |
michael@0 | 3875 | pass |
michael@0 | 3876 | |
michael@0 | 3877 | def p_Inheritance(self, p): |
michael@0 | 3878 | """ |
michael@0 | 3879 | Inheritance : COLON ScopedName |
michael@0 | 3880 | """ |
michael@0 | 3881 | p[0] = IDLIdentifierPlaceholder(self.getLocation(p, 2), p[2]) |
michael@0 | 3882 | |
michael@0 | 3883 | def p_InheritanceEmpty(self, p): |
michael@0 | 3884 | """ |
michael@0 | 3885 | Inheritance : |
michael@0 | 3886 | """ |
michael@0 | 3887 | pass |
michael@0 | 3888 | |
michael@0 | 3889 | def p_InterfaceMembers(self, p): |
michael@0 | 3890 | """ |
michael@0 | 3891 | InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers |
michael@0 | 3892 | """ |
michael@0 | 3893 | p[0] = [p[2]] if p[2] else [] |
michael@0 | 3894 | |
michael@0 | 3895 | assert not p[1] or p[2] |
michael@0 | 3896 | p[2].addExtendedAttributes(p[1]) |
michael@0 | 3897 | |
michael@0 | 3898 | p[0].extend(p[3]) |
michael@0 | 3899 | |
michael@0 | 3900 | def p_InterfaceMembersEmpty(self, p): |
michael@0 | 3901 | """ |
michael@0 | 3902 | InterfaceMembers : |
michael@0 | 3903 | """ |
michael@0 | 3904 | p[0] = [] |
michael@0 | 3905 | |
michael@0 | 3906 | def p_InterfaceMember(self, p): |
michael@0 | 3907 | """ |
michael@0 | 3908 | InterfaceMember : Const |
michael@0 | 3909 | | AttributeOrOperation |
michael@0 | 3910 | """ |
michael@0 | 3911 | p[0] = p[1] |
michael@0 | 3912 | |
michael@0 | 3913 | def p_Dictionary(self, p): |
michael@0 | 3914 | """ |
michael@0 | 3915 | Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON |
michael@0 | 3916 | """ |
michael@0 | 3917 | location = self.getLocation(p, 1) |
michael@0 | 3918 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) |
michael@0 | 3919 | members = p[5] |
michael@0 | 3920 | p[0] = IDLDictionary(location, self.globalScope(), identifier, p[3], members) |
michael@0 | 3921 | |
michael@0 | 3922 | def p_DictionaryMembers(self, p): |
michael@0 | 3923 | """ |
michael@0 | 3924 | DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers |
michael@0 | 3925 | | |
michael@0 | 3926 | """ |
michael@0 | 3927 | if len(p) == 1: |
michael@0 | 3928 | # We're at the end of the list |
michael@0 | 3929 | p[0] = [] |
michael@0 | 3930 | return |
michael@0 | 3931 | # Add our extended attributes |
michael@0 | 3932 | p[2].addExtendedAttributes(p[1]) |
michael@0 | 3933 | p[0] = [p[2]] |
michael@0 | 3934 | p[0].extend(p[3]) |
michael@0 | 3935 | |
michael@0 | 3936 | def p_DictionaryMember(self, p): |
michael@0 | 3937 | """ |
michael@0 | 3938 | DictionaryMember : Type IDENTIFIER DefaultValue SEMICOLON |
michael@0 | 3939 | """ |
michael@0 | 3940 | # These quack a lot like optional arguments, so just treat them that way. |
michael@0 | 3941 | t = p[1] |
michael@0 | 3942 | assert isinstance(t, IDLType) |
michael@0 | 3943 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) |
michael@0 | 3944 | defaultValue = p[3] |
michael@0 | 3945 | |
michael@0 | 3946 | p[0] = IDLArgument(self.getLocation(p, 2), identifier, t, optional=True, |
michael@0 | 3947 | defaultValue=defaultValue, variadic=False, |
michael@0 | 3948 | dictionaryMember=True) |
michael@0 | 3949 | |
michael@0 | 3950 | def p_DefaultValue(self, p): |
michael@0 | 3951 | """ |
michael@0 | 3952 | DefaultValue : EQUALS ConstValue |
michael@0 | 3953 | | |
michael@0 | 3954 | """ |
michael@0 | 3955 | if len(p) > 1: |
michael@0 | 3956 | p[0] = p[2] |
michael@0 | 3957 | else: |
michael@0 | 3958 | p[0] = None |
michael@0 | 3959 | |
michael@0 | 3960 | def p_Exception(self, p): |
michael@0 | 3961 | """ |
michael@0 | 3962 | Exception : EXCEPTION IDENTIFIER Inheritance LBRACE ExceptionMembers RBRACE SEMICOLON |
michael@0 | 3963 | """ |
michael@0 | 3964 | pass |
michael@0 | 3965 | |
michael@0 | 3966 | def p_Enum(self, p): |
michael@0 | 3967 | """ |
michael@0 | 3968 | Enum : ENUM IDENTIFIER LBRACE EnumValueList RBRACE SEMICOLON |
michael@0 | 3969 | """ |
michael@0 | 3970 | location = self.getLocation(p, 1) |
michael@0 | 3971 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) |
michael@0 | 3972 | |
michael@0 | 3973 | values = p[4] |
michael@0 | 3974 | assert values |
michael@0 | 3975 | p[0] = IDLEnum(location, self.globalScope(), identifier, values) |
michael@0 | 3976 | |
michael@0 | 3977 | def p_EnumValueList(self, p): |
michael@0 | 3978 | """ |
michael@0 | 3979 | EnumValueList : STRING EnumValueListComma |
michael@0 | 3980 | """ |
michael@0 | 3981 | p[0] = [p[1]] |
michael@0 | 3982 | p[0].extend(p[2]) |
michael@0 | 3983 | |
michael@0 | 3984 | def p_EnumValueListComma(self, p): |
michael@0 | 3985 | """ |
michael@0 | 3986 | EnumValueListComma : COMMA EnumValueListString |
michael@0 | 3987 | """ |
michael@0 | 3988 | p[0] = p[2] |
michael@0 | 3989 | |
michael@0 | 3990 | def p_EnumValueListCommaEmpty(self, p): |
michael@0 | 3991 | """ |
michael@0 | 3992 | EnumValueListComma : |
michael@0 | 3993 | """ |
michael@0 | 3994 | p[0] = [] |
michael@0 | 3995 | |
michael@0 | 3996 | def p_EnumValueListString(self, p): |
michael@0 | 3997 | """ |
michael@0 | 3998 | EnumValueListString : STRING EnumValueListComma |
michael@0 | 3999 | """ |
michael@0 | 4000 | p[0] = [p[1]] |
michael@0 | 4001 | p[0].extend(p[2]) |
michael@0 | 4002 | |
michael@0 | 4003 | def p_EnumValueListStringEmpty(self, p): |
michael@0 | 4004 | """ |
michael@0 | 4005 | EnumValueListString : |
michael@0 | 4006 | """ |
michael@0 | 4007 | p[0] = [] |
michael@0 | 4008 | |
michael@0 | 4009 | def p_CallbackRest(self, p): |
michael@0 | 4010 | """ |
michael@0 | 4011 | CallbackRest : IDENTIFIER EQUALS ReturnType LPAREN ArgumentList RPAREN SEMICOLON |
michael@0 | 4012 | """ |
michael@0 | 4013 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) |
michael@0 | 4014 | p[0] = IDLCallbackType(self.getLocation(p, 1), self.globalScope(), |
michael@0 | 4015 | identifier, p[3], p[5]) |
michael@0 | 4016 | |
michael@0 | 4017 | def p_ExceptionMembers(self, p): |
michael@0 | 4018 | """ |
michael@0 | 4019 | ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers |
michael@0 | 4020 | | |
michael@0 | 4021 | """ |
michael@0 | 4022 | pass |
michael@0 | 4023 | |
michael@0 | 4024 | def p_Typedef(self, p): |
michael@0 | 4025 | """ |
michael@0 | 4026 | Typedef : TYPEDEF Type IDENTIFIER SEMICOLON |
michael@0 | 4027 | """ |
michael@0 | 4028 | typedef = IDLTypedefType(self.getLocation(p, 1), p[2], p[3]) |
michael@0 | 4029 | typedef.resolve(self.globalScope()) |
michael@0 | 4030 | p[0] = typedef |
michael@0 | 4031 | |
michael@0 | 4032 | def p_ImplementsStatement(self, p): |
michael@0 | 4033 | """ |
michael@0 | 4034 | ImplementsStatement : ScopedName IMPLEMENTS ScopedName SEMICOLON |
michael@0 | 4035 | """ |
michael@0 | 4036 | assert(p[2] == "implements") |
michael@0 | 4037 | implementor = IDLIdentifierPlaceholder(self.getLocation(p, 1), p[1]) |
michael@0 | 4038 | implementee = IDLIdentifierPlaceholder(self.getLocation(p, 3), p[3]) |
michael@0 | 4039 | p[0] = IDLImplementsStatement(self.getLocation(p, 1), implementor, |
michael@0 | 4040 | implementee) |
michael@0 | 4041 | |
michael@0 | 4042 | def p_Const(self, p): |
michael@0 | 4043 | """ |
michael@0 | 4044 | Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON |
michael@0 | 4045 | """ |
michael@0 | 4046 | location = self.getLocation(p, 1) |
michael@0 | 4047 | type = p[2] |
michael@0 | 4048 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) |
michael@0 | 4049 | value = p[5] |
michael@0 | 4050 | p[0] = IDLConst(location, identifier, type, value) |
michael@0 | 4051 | |
michael@0 | 4052 | def p_ConstValueBoolean(self, p): |
michael@0 | 4053 | """ |
michael@0 | 4054 | ConstValue : BooleanLiteral |
michael@0 | 4055 | """ |
michael@0 | 4056 | location = self.getLocation(p, 1) |
michael@0 | 4057 | booleanType = BuiltinTypes[IDLBuiltinType.Types.boolean] |
michael@0 | 4058 | p[0] = IDLValue(location, booleanType, p[1]) |
michael@0 | 4059 | |
michael@0 | 4060 | def p_ConstValueInteger(self, p): |
michael@0 | 4061 | """ |
michael@0 | 4062 | ConstValue : INTEGER |
michael@0 | 4063 | """ |
michael@0 | 4064 | location = self.getLocation(p, 1) |
michael@0 | 4065 | |
michael@0 | 4066 | # We don't know ahead of time what type the integer literal is. |
michael@0 | 4067 | # Determine the smallest type it could possibly fit in and use that. |
michael@0 | 4068 | integerType = matchIntegerValueToType(p[1]) |
michael@0 | 4069 | if integerType == None: |
michael@0 | 4070 | raise WebIDLError("Integer literal out of range", [location]) |
michael@0 | 4071 | |
michael@0 | 4072 | p[0] = IDLValue(location, integerType, p[1]) |
michael@0 | 4073 | |
michael@0 | 4074 | def p_ConstValueFloat(self, p): |
michael@0 | 4075 | """ |
michael@0 | 4076 | ConstValue : FLOATLITERAL |
michael@0 | 4077 | """ |
michael@0 | 4078 | location = self.getLocation(p, 1) |
michael@0 | 4079 | p[0] = IDLValue(location, BuiltinTypes[IDLBuiltinType.Types.unrestricted_float], p[1]) |
michael@0 | 4080 | |
michael@0 | 4081 | def p_ConstValueString(self, p): |
michael@0 | 4082 | """ |
michael@0 | 4083 | ConstValue : STRING |
michael@0 | 4084 | """ |
michael@0 | 4085 | location = self.getLocation(p, 1) |
michael@0 | 4086 | stringType = BuiltinTypes[IDLBuiltinType.Types.domstring] |
michael@0 | 4087 | p[0] = IDLValue(location, stringType, p[1]) |
michael@0 | 4088 | |
michael@0 | 4089 | def p_ConstValueNull(self, p): |
michael@0 | 4090 | """ |
michael@0 | 4091 | ConstValue : NULL |
michael@0 | 4092 | """ |
michael@0 | 4093 | p[0] = IDLNullValue(self.getLocation(p, 1)) |
michael@0 | 4094 | |
michael@0 | 4095 | def p_BooleanLiteralTrue(self, p): |
michael@0 | 4096 | """ |
michael@0 | 4097 | BooleanLiteral : TRUE |
michael@0 | 4098 | """ |
michael@0 | 4099 | p[0] = True |
michael@0 | 4100 | |
michael@0 | 4101 | def p_BooleanLiteralFalse(self, p): |
michael@0 | 4102 | """ |
michael@0 | 4103 | BooleanLiteral : FALSE |
michael@0 | 4104 | """ |
michael@0 | 4105 | p[0] = False |
michael@0 | 4106 | |
michael@0 | 4107 | def p_AttributeOrOperation(self, p): |
michael@0 | 4108 | """ |
michael@0 | 4109 | AttributeOrOperation : Attribute |
michael@0 | 4110 | | Operation |
michael@0 | 4111 | """ |
michael@0 | 4112 | p[0] = p[1] |
michael@0 | 4113 | |
michael@0 | 4114 | def p_AttributeWithQualifier(self, p): |
michael@0 | 4115 | """ |
michael@0 | 4116 | Attribute : Qualifier AttributeRest |
michael@0 | 4117 | """ |
michael@0 | 4118 | static = IDLInterfaceMember.Special.Static in p[1] |
michael@0 | 4119 | stringifier = IDLInterfaceMember.Special.Stringifier in p[1] |
michael@0 | 4120 | (location, identifier, type, readonly) = p[2] |
michael@0 | 4121 | p[0] = IDLAttribute(location, identifier, type, readonly, static=static, |
michael@0 | 4122 | stringifier=stringifier) |
michael@0 | 4123 | |
michael@0 | 4124 | def p_Attribute(self, p): |
michael@0 | 4125 | """ |
michael@0 | 4126 | Attribute : Inherit AttributeRest |
michael@0 | 4127 | """ |
michael@0 | 4128 | (location, identifier, type, readonly) = p[2] |
michael@0 | 4129 | p[0] = IDLAttribute(location, identifier, type, readonly, inherit=p[1]) |
michael@0 | 4130 | |
michael@0 | 4131 | def p_AttributeRest(self, p): |
michael@0 | 4132 | """ |
michael@0 | 4133 | AttributeRest : ReadOnly ATTRIBUTE Type IDENTIFIER SEMICOLON |
michael@0 | 4134 | """ |
michael@0 | 4135 | location = self.getLocation(p, 2) |
michael@0 | 4136 | readonly = p[1] |
michael@0 | 4137 | t = p[3] |
michael@0 | 4138 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 4), p[4]) |
michael@0 | 4139 | p[0] = (location, identifier, t, readonly) |
michael@0 | 4140 | |
michael@0 | 4141 | def p_ReadOnly(self, p): |
michael@0 | 4142 | """ |
michael@0 | 4143 | ReadOnly : READONLY |
michael@0 | 4144 | """ |
michael@0 | 4145 | p[0] = True |
michael@0 | 4146 | |
michael@0 | 4147 | def p_ReadOnlyEmpty(self, p): |
michael@0 | 4148 | """ |
michael@0 | 4149 | ReadOnly : |
michael@0 | 4150 | """ |
michael@0 | 4151 | p[0] = False |
michael@0 | 4152 | |
michael@0 | 4153 | def p_Inherit(self, p): |
michael@0 | 4154 | """ |
michael@0 | 4155 | Inherit : INHERIT |
michael@0 | 4156 | """ |
michael@0 | 4157 | p[0] = True |
michael@0 | 4158 | |
michael@0 | 4159 | def p_InheritEmpty(self, p): |
michael@0 | 4160 | """ |
michael@0 | 4161 | Inherit : |
michael@0 | 4162 | """ |
michael@0 | 4163 | p[0] = False |
michael@0 | 4164 | |
michael@0 | 4165 | def p_Operation(self, p): |
michael@0 | 4166 | """ |
michael@0 | 4167 | Operation : Qualifiers OperationRest |
michael@0 | 4168 | """ |
michael@0 | 4169 | qualifiers = p[1] |
michael@0 | 4170 | |
michael@0 | 4171 | # Disallow duplicates in the qualifier set |
michael@0 | 4172 | if not len(set(qualifiers)) == len(qualifiers): |
michael@0 | 4173 | raise WebIDLError("Duplicate qualifiers are not allowed", |
michael@0 | 4174 | [self.getLocation(p, 1)]) |
michael@0 | 4175 | |
michael@0 | 4176 | static = IDLInterfaceMember.Special.Static in p[1] |
michael@0 | 4177 | # If static is there that's all that's allowed. This is disallowed |
michael@0 | 4178 | # by the parser, so we can assert here. |
michael@0 | 4179 | assert not static or len(qualifiers) == 1 |
michael@0 | 4180 | |
michael@0 | 4181 | stringifier = IDLInterfaceMember.Special.Stringifier in p[1] |
michael@0 | 4182 | # If stringifier is there that's all that's allowed. This is disallowed |
michael@0 | 4183 | # by the parser, so we can assert here. |
michael@0 | 4184 | assert not stringifier or len(qualifiers) == 1 |
michael@0 | 4185 | |
michael@0 | 4186 | getter = True if IDLMethod.Special.Getter in p[1] else False |
michael@0 | 4187 | setter = True if IDLMethod.Special.Setter in p[1] else False |
michael@0 | 4188 | creator = True if IDLMethod.Special.Creator in p[1] else False |
michael@0 | 4189 | deleter = True if IDLMethod.Special.Deleter in p[1] else False |
michael@0 | 4190 | legacycaller = True if IDLMethod.Special.LegacyCaller in p[1] else False |
michael@0 | 4191 | |
michael@0 | 4192 | if getter or deleter: |
michael@0 | 4193 | if setter or creator: |
michael@0 | 4194 | raise WebIDLError("getter and deleter are incompatible with setter and creator", |
michael@0 | 4195 | [self.getLocation(p, 1)]) |
michael@0 | 4196 | |
michael@0 | 4197 | (returnType, identifier, arguments) = p[2] |
michael@0 | 4198 | |
michael@0 | 4199 | assert isinstance(returnType, IDLType) |
michael@0 | 4200 | |
michael@0 | 4201 | specialType = IDLMethod.NamedOrIndexed.Neither |
michael@0 | 4202 | |
michael@0 | 4203 | if getter or deleter: |
michael@0 | 4204 | if len(arguments) != 1: |
michael@0 | 4205 | raise WebIDLError("%s has wrong number of arguments" % |
michael@0 | 4206 | ("getter" if getter else "deleter"), |
michael@0 | 4207 | [self.getLocation(p, 2)]) |
michael@0 | 4208 | argType = arguments[0].type |
michael@0 | 4209 | if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: |
michael@0 | 4210 | specialType = IDLMethod.NamedOrIndexed.Named |
michael@0 | 4211 | elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: |
michael@0 | 4212 | specialType = IDLMethod.NamedOrIndexed.Indexed |
michael@0 | 4213 | else: |
michael@0 | 4214 | raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" % |
michael@0 | 4215 | ("getter" if getter else "deleter"), |
michael@0 | 4216 | [arguments[0].location]) |
michael@0 | 4217 | if arguments[0].optional or arguments[0].variadic: |
michael@0 | 4218 | raise WebIDLError("%s cannot have %s argument" % |
michael@0 | 4219 | ("getter" if getter else "deleter", |
michael@0 | 4220 | "optional" if arguments[0].optional else "variadic"), |
michael@0 | 4221 | [arguments[0].location]) |
michael@0 | 4222 | if getter: |
michael@0 | 4223 | if returnType.isVoid(): |
michael@0 | 4224 | raise WebIDLError("getter cannot have void return type", |
michael@0 | 4225 | [self.getLocation(p, 2)]) |
michael@0 | 4226 | if setter or creator: |
michael@0 | 4227 | if len(arguments) != 2: |
michael@0 | 4228 | raise WebIDLError("%s has wrong number of arguments" % |
michael@0 | 4229 | ("setter" if setter else "creator"), |
michael@0 | 4230 | [self.getLocation(p, 2)]) |
michael@0 | 4231 | argType = arguments[0].type |
michael@0 | 4232 | if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: |
michael@0 | 4233 | specialType = IDLMethod.NamedOrIndexed.Named |
michael@0 | 4234 | elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: |
michael@0 | 4235 | specialType = IDLMethod.NamedOrIndexed.Indexed |
michael@0 | 4236 | else: |
michael@0 | 4237 | raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" % |
michael@0 | 4238 | ("setter" if setter else "creator"), |
michael@0 | 4239 | [arguments[0].location]) |
michael@0 | 4240 | if arguments[0].optional or arguments[0].variadic: |
michael@0 | 4241 | raise WebIDLError("%s cannot have %s argument" % |
michael@0 | 4242 | ("setter" if setter else "creator", |
michael@0 | 4243 | "optional" if arguments[0].optional else "variadic"), |
michael@0 | 4244 | [arguments[0].location]) |
michael@0 | 4245 | if arguments[1].optional or arguments[1].variadic: |
michael@0 | 4246 | raise WebIDLError("%s cannot have %s argument" % |
michael@0 | 4247 | ("setter" if setter else "creator", |
michael@0 | 4248 | "optional" if arguments[1].optional else "variadic"), |
michael@0 | 4249 | [arguments[1].location]) |
michael@0 | 4250 | |
michael@0 | 4251 | if stringifier: |
michael@0 | 4252 | if len(arguments) != 0: |
michael@0 | 4253 | raise WebIDLError("stringifier has wrong number of arguments", |
michael@0 | 4254 | [self.getLocation(p, 2)]) |
michael@0 | 4255 | if not returnType.isDOMString(): |
michael@0 | 4256 | raise WebIDLError("stringifier must have DOMString return type", |
michael@0 | 4257 | [self.getLocation(p, 2)]) |
michael@0 | 4258 | |
michael@0 | 4259 | # identifier might be None. This is only permitted for special methods. |
michael@0 | 4260 | if not identifier: |
michael@0 | 4261 | if not getter and not setter and not creator and \ |
michael@0 | 4262 | not deleter and not legacycaller and not stringifier: |
michael@0 | 4263 | raise WebIDLError("Identifier required for non-special methods", |
michael@0 | 4264 | [self.getLocation(p, 2)]) |
michael@0 | 4265 | |
michael@0 | 4266 | location = BuiltinLocation("<auto-generated-identifier>") |
michael@0 | 4267 | identifier = IDLUnresolvedIdentifier(location, "__%s%s%s%s%s%s%s" % |
michael@0 | 4268 | ("named" if specialType == IDLMethod.NamedOrIndexed.Named else \ |
michael@0 | 4269 | "indexed" if specialType == IDLMethod.NamedOrIndexed.Indexed else "", |
michael@0 | 4270 | "getter" if getter else "", |
michael@0 | 4271 | "setter" if setter else "", |
michael@0 | 4272 | "deleter" if deleter else "", |
michael@0 | 4273 | "creator" if creator else "", |
michael@0 | 4274 | "legacycaller" if legacycaller else "", |
michael@0 | 4275 | "stringifier" if stringifier else ""), allowDoubleUnderscore=True) |
michael@0 | 4276 | |
michael@0 | 4277 | method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments, |
michael@0 | 4278 | static=static, getter=getter, setter=setter, creator=creator, |
michael@0 | 4279 | deleter=deleter, specialType=specialType, |
michael@0 | 4280 | legacycaller=legacycaller, stringifier=stringifier) |
michael@0 | 4281 | p[0] = method |
michael@0 | 4282 | |
michael@0 | 4283 | def p_Stringifier(self, p): |
michael@0 | 4284 | """ |
michael@0 | 4285 | Operation : STRINGIFIER SEMICOLON |
michael@0 | 4286 | """ |
michael@0 | 4287 | identifier = IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), |
michael@0 | 4288 | "__stringifier", |
michael@0 | 4289 | allowDoubleUnderscore=True) |
michael@0 | 4290 | method = IDLMethod(self.getLocation(p, 1), |
michael@0 | 4291 | identifier, |
michael@0 | 4292 | returnType=BuiltinTypes[IDLBuiltinType.Types.domstring], |
michael@0 | 4293 | arguments=[], |
michael@0 | 4294 | stringifier=True) |
michael@0 | 4295 | p[0] = method |
michael@0 | 4296 | |
michael@0 | 4297 | def p_Jsonifier(self, p): |
michael@0 | 4298 | """ |
michael@0 | 4299 | Operation : JSONIFIER SEMICOLON |
michael@0 | 4300 | """ |
michael@0 | 4301 | identifier = IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), |
michael@0 | 4302 | "__jsonifier", allowDoubleUnderscore=True) |
michael@0 | 4303 | method = IDLMethod(self.getLocation(p, 1), |
michael@0 | 4304 | identifier, |
michael@0 | 4305 | returnType=BuiltinTypes[IDLBuiltinType.Types.object], |
michael@0 | 4306 | arguments=[], |
michael@0 | 4307 | jsonifier=True) |
michael@0 | 4308 | p[0] = method |
michael@0 | 4309 | |
michael@0 | 4310 | def p_QualifierStatic(self, p): |
michael@0 | 4311 | """ |
michael@0 | 4312 | Qualifier : STATIC |
michael@0 | 4313 | """ |
michael@0 | 4314 | p[0] = [IDLInterfaceMember.Special.Static] |
michael@0 | 4315 | |
michael@0 | 4316 | def p_QualifierStringifier(self, p): |
michael@0 | 4317 | """ |
michael@0 | 4318 | Qualifier : STRINGIFIER |
michael@0 | 4319 | """ |
michael@0 | 4320 | p[0] = [IDLInterfaceMember.Special.Stringifier] |
michael@0 | 4321 | |
michael@0 | 4322 | def p_Qualifiers(self, p): |
michael@0 | 4323 | """ |
michael@0 | 4324 | Qualifiers : Qualifier |
michael@0 | 4325 | | Specials |
michael@0 | 4326 | """ |
michael@0 | 4327 | p[0] = p[1] |
michael@0 | 4328 | |
michael@0 | 4329 | def p_Specials(self, p): |
michael@0 | 4330 | """ |
michael@0 | 4331 | Specials : Special Specials |
michael@0 | 4332 | """ |
michael@0 | 4333 | p[0] = [p[1]] |
michael@0 | 4334 | p[0].extend(p[2]) |
michael@0 | 4335 | |
michael@0 | 4336 | def p_SpecialsEmpty(self, p): |
michael@0 | 4337 | """ |
michael@0 | 4338 | Specials : |
michael@0 | 4339 | """ |
michael@0 | 4340 | p[0] = [] |
michael@0 | 4341 | |
michael@0 | 4342 | def p_SpecialGetter(self, p): |
michael@0 | 4343 | """ |
michael@0 | 4344 | Special : GETTER |
michael@0 | 4345 | """ |
michael@0 | 4346 | p[0] = IDLMethod.Special.Getter |
michael@0 | 4347 | |
michael@0 | 4348 | def p_SpecialSetter(self, p): |
michael@0 | 4349 | """ |
michael@0 | 4350 | Special : SETTER |
michael@0 | 4351 | """ |
michael@0 | 4352 | p[0] = IDLMethod.Special.Setter |
michael@0 | 4353 | |
michael@0 | 4354 | def p_SpecialCreator(self, p): |
michael@0 | 4355 | """ |
michael@0 | 4356 | Special : CREATOR |
michael@0 | 4357 | """ |
michael@0 | 4358 | p[0] = IDLMethod.Special.Creator |
michael@0 | 4359 | |
michael@0 | 4360 | def p_SpecialDeleter(self, p): |
michael@0 | 4361 | """ |
michael@0 | 4362 | Special : DELETER |
michael@0 | 4363 | """ |
michael@0 | 4364 | p[0] = IDLMethod.Special.Deleter |
michael@0 | 4365 | |
michael@0 | 4366 | def p_SpecialLegacyCaller(self, p): |
michael@0 | 4367 | """ |
michael@0 | 4368 | Special : LEGACYCALLER |
michael@0 | 4369 | """ |
michael@0 | 4370 | p[0] = IDLMethod.Special.LegacyCaller |
michael@0 | 4371 | |
michael@0 | 4372 | def p_OperationRest(self, p): |
michael@0 | 4373 | """ |
michael@0 | 4374 | OperationRest : ReturnType OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON |
michael@0 | 4375 | """ |
michael@0 | 4376 | p[0] = (p[1], p[2], p[4]) |
michael@0 | 4377 | |
michael@0 | 4378 | def p_OptionalIdentifier(self, p): |
michael@0 | 4379 | """ |
michael@0 | 4380 | OptionalIdentifier : IDENTIFIER |
michael@0 | 4381 | """ |
michael@0 | 4382 | p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) |
michael@0 | 4383 | |
michael@0 | 4384 | def p_OptionalIdentifierEmpty(self, p): |
michael@0 | 4385 | """ |
michael@0 | 4386 | OptionalIdentifier : |
michael@0 | 4387 | """ |
michael@0 | 4388 | pass |
michael@0 | 4389 | |
michael@0 | 4390 | def p_ArgumentList(self, p): |
michael@0 | 4391 | """ |
michael@0 | 4392 | ArgumentList : Argument Arguments |
michael@0 | 4393 | """ |
michael@0 | 4394 | p[0] = [p[1]] if p[1] else [] |
michael@0 | 4395 | p[0].extend(p[2]) |
michael@0 | 4396 | |
michael@0 | 4397 | def p_ArgumentListEmpty(self, p): |
michael@0 | 4398 | """ |
michael@0 | 4399 | ArgumentList : |
michael@0 | 4400 | """ |
michael@0 | 4401 | p[0] = [] |
michael@0 | 4402 | |
michael@0 | 4403 | def p_Arguments(self, p): |
michael@0 | 4404 | """ |
michael@0 | 4405 | Arguments : COMMA Argument Arguments |
michael@0 | 4406 | """ |
michael@0 | 4407 | p[0] = [p[2]] if p[2] else [] |
michael@0 | 4408 | p[0].extend(p[3]) |
michael@0 | 4409 | |
michael@0 | 4410 | def p_ArgumentsEmpty(self, p): |
michael@0 | 4411 | """ |
michael@0 | 4412 | Arguments : |
michael@0 | 4413 | """ |
michael@0 | 4414 | p[0] = [] |
michael@0 | 4415 | |
michael@0 | 4416 | def p_Argument(self, p): |
michael@0 | 4417 | """ |
michael@0 | 4418 | Argument : ExtendedAttributeList Optional Type Ellipsis ArgumentName DefaultValue |
michael@0 | 4419 | """ |
michael@0 | 4420 | t = p[3] |
michael@0 | 4421 | assert isinstance(t, IDLType) |
michael@0 | 4422 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 5), p[5]) |
michael@0 | 4423 | |
michael@0 | 4424 | optional = p[2] |
michael@0 | 4425 | variadic = p[4] |
michael@0 | 4426 | defaultValue = p[6] |
michael@0 | 4427 | |
michael@0 | 4428 | if not optional and defaultValue: |
michael@0 | 4429 | raise WebIDLError("Mandatory arguments can't have a default value.", |
michael@0 | 4430 | [self.getLocation(p, 6)]) |
michael@0 | 4431 | |
michael@0 | 4432 | # We can't test t.isAny() here and give it a default value as needed, |
michael@0 | 4433 | # since at this point t is not a fully resolved type yet (e.g. it might |
michael@0 | 4434 | # be a typedef). We'll handle the 'any' case in IDLArgument.complete. |
michael@0 | 4435 | |
michael@0 | 4436 | if variadic: |
michael@0 | 4437 | if optional: |
michael@0 | 4438 | raise WebIDLError("Variadic arguments should not be marked optional.", |
michael@0 | 4439 | [self.getLocation(p, 2)]) |
michael@0 | 4440 | optional = variadic |
michael@0 | 4441 | |
michael@0 | 4442 | p[0] = IDLArgument(self.getLocation(p, 5), identifier, t, optional, defaultValue, variadic) |
michael@0 | 4443 | p[0].addExtendedAttributes(p[1]) |
michael@0 | 4444 | |
michael@0 | 4445 | def p_ArgumentName(self, p): |
michael@0 | 4446 | """ |
michael@0 | 4447 | ArgumentName : IDENTIFIER |
michael@0 | 4448 | | ATTRIBUTE |
michael@0 | 4449 | | CALLBACK |
michael@0 | 4450 | | CONST |
michael@0 | 4451 | | CREATOR |
michael@0 | 4452 | | DELETER |
michael@0 | 4453 | | DICTIONARY |
michael@0 | 4454 | | ENUM |
michael@0 | 4455 | | EXCEPTION |
michael@0 | 4456 | | GETTER |
michael@0 | 4457 | | IMPLEMENTS |
michael@0 | 4458 | | INHERIT |
michael@0 | 4459 | | INTERFACE |
michael@0 | 4460 | | LEGACYCALLER |
michael@0 | 4461 | | PARTIAL |
michael@0 | 4462 | | SERIALIZER |
michael@0 | 4463 | | SETTER |
michael@0 | 4464 | | STATIC |
michael@0 | 4465 | | STRINGIFIER |
michael@0 | 4466 | | JSONIFIER |
michael@0 | 4467 | | TYPEDEF |
michael@0 | 4468 | | UNRESTRICTED |
michael@0 | 4469 | """ |
michael@0 | 4470 | p[0] = p[1] |
michael@0 | 4471 | |
michael@0 | 4472 | def p_Optional(self, p): |
michael@0 | 4473 | """ |
michael@0 | 4474 | Optional : OPTIONAL |
michael@0 | 4475 | """ |
michael@0 | 4476 | p[0] = True |
michael@0 | 4477 | |
michael@0 | 4478 | def p_OptionalEmpty(self, p): |
michael@0 | 4479 | """ |
michael@0 | 4480 | Optional : |
michael@0 | 4481 | """ |
michael@0 | 4482 | p[0] = False |
michael@0 | 4483 | |
michael@0 | 4484 | def p_Ellipsis(self, p): |
michael@0 | 4485 | """ |
michael@0 | 4486 | Ellipsis : ELLIPSIS |
michael@0 | 4487 | """ |
michael@0 | 4488 | p[0] = True |
michael@0 | 4489 | |
michael@0 | 4490 | def p_EllipsisEmpty(self, p): |
michael@0 | 4491 | """ |
michael@0 | 4492 | Ellipsis : |
michael@0 | 4493 | """ |
michael@0 | 4494 | p[0] = False |
michael@0 | 4495 | |
michael@0 | 4496 | def p_ExceptionMember(self, p): |
michael@0 | 4497 | """ |
michael@0 | 4498 | ExceptionMember : Const |
michael@0 | 4499 | | ExceptionField |
michael@0 | 4500 | """ |
michael@0 | 4501 | pass |
michael@0 | 4502 | |
michael@0 | 4503 | def p_ExceptionField(self, p): |
michael@0 | 4504 | """ |
michael@0 | 4505 | ExceptionField : Type IDENTIFIER SEMICOLON |
michael@0 | 4506 | """ |
michael@0 | 4507 | pass |
michael@0 | 4508 | |
michael@0 | 4509 | def p_ExtendedAttributeList(self, p): |
michael@0 | 4510 | """ |
michael@0 | 4511 | ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET |
michael@0 | 4512 | """ |
michael@0 | 4513 | p[0] = [p[2]] |
michael@0 | 4514 | if p[3]: |
michael@0 | 4515 | p[0].extend(p[3]) |
michael@0 | 4516 | |
michael@0 | 4517 | def p_ExtendedAttributeListEmpty(self, p): |
michael@0 | 4518 | """ |
michael@0 | 4519 | ExtendedAttributeList : |
michael@0 | 4520 | """ |
michael@0 | 4521 | p[0] = [] |
michael@0 | 4522 | |
michael@0 | 4523 | def p_ExtendedAttribute(self, p): |
michael@0 | 4524 | """ |
michael@0 | 4525 | ExtendedAttribute : ExtendedAttributeNoArgs |
michael@0 | 4526 | | ExtendedAttributeArgList |
michael@0 | 4527 | | ExtendedAttributeIdent |
michael@0 | 4528 | | ExtendedAttributeNamedArgList |
michael@0 | 4529 | """ |
michael@0 | 4530 | p[0] = IDLExtendedAttribute(self.getLocation(p, 1), p[1]) |
michael@0 | 4531 | |
michael@0 | 4532 | def p_ExtendedAttributeEmpty(self, p): |
michael@0 | 4533 | """ |
michael@0 | 4534 | ExtendedAttribute : |
michael@0 | 4535 | """ |
michael@0 | 4536 | pass |
michael@0 | 4537 | |
michael@0 | 4538 | def p_ExtendedAttributes(self, p): |
michael@0 | 4539 | """ |
michael@0 | 4540 | ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes |
michael@0 | 4541 | """ |
michael@0 | 4542 | p[0] = [p[2]] if p[2] else [] |
michael@0 | 4543 | p[0].extend(p[3]) |
michael@0 | 4544 | |
michael@0 | 4545 | def p_ExtendedAttributesEmpty(self, p): |
michael@0 | 4546 | """ |
michael@0 | 4547 | ExtendedAttributes : |
michael@0 | 4548 | """ |
michael@0 | 4549 | p[0] = [] |
michael@0 | 4550 | |
michael@0 | 4551 | def p_Other(self, p): |
michael@0 | 4552 | """ |
michael@0 | 4553 | Other : INTEGER |
michael@0 | 4554 | | FLOATLITERAL |
michael@0 | 4555 | | IDENTIFIER |
michael@0 | 4556 | | STRING |
michael@0 | 4557 | | OTHER |
michael@0 | 4558 | | ELLIPSIS |
michael@0 | 4559 | | COLON |
michael@0 | 4560 | | SCOPE |
michael@0 | 4561 | | SEMICOLON |
michael@0 | 4562 | | LT |
michael@0 | 4563 | | EQUALS |
michael@0 | 4564 | | GT |
michael@0 | 4565 | | QUESTIONMARK |
michael@0 | 4566 | | DATE |
michael@0 | 4567 | | DOMSTRING |
michael@0 | 4568 | | BYTESTRING |
michael@0 | 4569 | | ANY |
michael@0 | 4570 | | ATTRIBUTE |
michael@0 | 4571 | | BOOLEAN |
michael@0 | 4572 | | BYTE |
michael@0 | 4573 | | LEGACYCALLER |
michael@0 | 4574 | | CONST |
michael@0 | 4575 | | CREATOR |
michael@0 | 4576 | | DELETER |
michael@0 | 4577 | | DOUBLE |
michael@0 | 4578 | | EXCEPTION |
michael@0 | 4579 | | FALSE |
michael@0 | 4580 | | FLOAT |
michael@0 | 4581 | | GETTER |
michael@0 | 4582 | | IMPLEMENTS |
michael@0 | 4583 | | INHERIT |
michael@0 | 4584 | | INTERFACE |
michael@0 | 4585 | | LONG |
michael@0 | 4586 | | MODULE |
michael@0 | 4587 | | NULL |
michael@0 | 4588 | | OBJECT |
michael@0 | 4589 | | OCTET |
michael@0 | 4590 | | OPTIONAL |
michael@0 | 4591 | | SEQUENCE |
michael@0 | 4592 | | MOZMAP |
michael@0 | 4593 | | SETTER |
michael@0 | 4594 | | SHORT |
michael@0 | 4595 | | STATIC |
michael@0 | 4596 | | STRINGIFIER |
michael@0 | 4597 | | JSONIFIER |
michael@0 | 4598 | | TRUE |
michael@0 | 4599 | | TYPEDEF |
michael@0 | 4600 | | UNSIGNED |
michael@0 | 4601 | | VOID |
michael@0 | 4602 | """ |
michael@0 | 4603 | pass |
michael@0 | 4604 | |
michael@0 | 4605 | def p_OtherOrComma(self, p): |
michael@0 | 4606 | """ |
michael@0 | 4607 | OtherOrComma : Other |
michael@0 | 4608 | | COMMA |
michael@0 | 4609 | """ |
michael@0 | 4610 | pass |
michael@0 | 4611 | |
michael@0 | 4612 | def p_TypeSingleType(self, p): |
michael@0 | 4613 | """ |
michael@0 | 4614 | Type : SingleType |
michael@0 | 4615 | """ |
michael@0 | 4616 | p[0] = p[1] |
michael@0 | 4617 | |
michael@0 | 4618 | def p_TypeUnionType(self, p): |
michael@0 | 4619 | """ |
michael@0 | 4620 | Type : UnionType TypeSuffix |
michael@0 | 4621 | """ |
michael@0 | 4622 | p[0] = self.handleModifiers(p[1], p[2]) |
michael@0 | 4623 | |
michael@0 | 4624 | def p_SingleTypeNonAnyType(self, p): |
michael@0 | 4625 | """ |
michael@0 | 4626 | SingleType : NonAnyType |
michael@0 | 4627 | """ |
michael@0 | 4628 | p[0] = p[1] |
michael@0 | 4629 | |
michael@0 | 4630 | def p_SingleTypeAnyType(self, p): |
michael@0 | 4631 | """ |
michael@0 | 4632 | SingleType : ANY TypeSuffixStartingWithArray |
michael@0 | 4633 | """ |
michael@0 | 4634 | p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.any], p[2]) |
michael@0 | 4635 | |
michael@0 | 4636 | def p_UnionType(self, p): |
michael@0 | 4637 | """ |
michael@0 | 4638 | UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN |
michael@0 | 4639 | """ |
michael@0 | 4640 | types = [p[2], p[4]] |
michael@0 | 4641 | types.extend(p[5]) |
michael@0 | 4642 | p[0] = IDLUnionType(self.getLocation(p, 1), types) |
michael@0 | 4643 | |
michael@0 | 4644 | def p_UnionMemberTypeNonAnyType(self, p): |
michael@0 | 4645 | """ |
michael@0 | 4646 | UnionMemberType : NonAnyType |
michael@0 | 4647 | """ |
michael@0 | 4648 | p[0] = p[1] |
michael@0 | 4649 | |
michael@0 | 4650 | def p_UnionMemberTypeArrayOfAny(self, p): |
michael@0 | 4651 | """ |
michael@0 | 4652 | UnionMemberTypeArrayOfAny : ANY LBRACKET RBRACKET |
michael@0 | 4653 | """ |
michael@0 | 4654 | p[0] = IDLArrayType(self.getLocation(p, 2), |
michael@0 | 4655 | BuiltinTypes[IDLBuiltinType.Types.any]) |
michael@0 | 4656 | |
michael@0 | 4657 | def p_UnionMemberType(self, p): |
michael@0 | 4658 | """ |
michael@0 | 4659 | UnionMemberType : UnionType TypeSuffix |
michael@0 | 4660 | | UnionMemberTypeArrayOfAny TypeSuffix |
michael@0 | 4661 | """ |
michael@0 | 4662 | p[0] = self.handleModifiers(p[1], p[2]) |
michael@0 | 4663 | |
michael@0 | 4664 | def p_UnionMemberTypes(self, p): |
michael@0 | 4665 | """ |
michael@0 | 4666 | UnionMemberTypes : OR UnionMemberType UnionMemberTypes |
michael@0 | 4667 | """ |
michael@0 | 4668 | p[0] = [p[2]] |
michael@0 | 4669 | p[0].extend(p[3]) |
michael@0 | 4670 | |
michael@0 | 4671 | def p_UnionMemberTypesEmpty(self, p): |
michael@0 | 4672 | """ |
michael@0 | 4673 | UnionMemberTypes : |
michael@0 | 4674 | """ |
michael@0 | 4675 | p[0] = [] |
michael@0 | 4676 | |
michael@0 | 4677 | def p_NonAnyType(self, p): |
michael@0 | 4678 | """ |
michael@0 | 4679 | NonAnyType : PrimitiveOrStringType TypeSuffix |
michael@0 | 4680 | | ARRAYBUFFER TypeSuffix |
michael@0 | 4681 | | OBJECT TypeSuffix |
michael@0 | 4682 | """ |
michael@0 | 4683 | if p[1] == "object": |
michael@0 | 4684 | type = BuiltinTypes[IDLBuiltinType.Types.object] |
michael@0 | 4685 | elif p[1] == "ArrayBuffer": |
michael@0 | 4686 | type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer] |
michael@0 | 4687 | else: |
michael@0 | 4688 | type = BuiltinTypes[p[1]] |
michael@0 | 4689 | |
michael@0 | 4690 | p[0] = self.handleModifiers(type, p[2]) |
michael@0 | 4691 | |
michael@0 | 4692 | def p_NonAnyTypeSequenceType(self, p): |
michael@0 | 4693 | """ |
michael@0 | 4694 | NonAnyType : SEQUENCE LT Type GT Null |
michael@0 | 4695 | """ |
michael@0 | 4696 | innerType = p[3] |
michael@0 | 4697 | type = IDLSequenceType(self.getLocation(p, 1), innerType) |
michael@0 | 4698 | if p[5]: |
michael@0 | 4699 | type = IDLNullableType(self.getLocation(p, 5), type) |
michael@0 | 4700 | p[0] = type |
michael@0 | 4701 | |
michael@0 | 4702 | def p_NonAnyTypeMozMapType(self, p): |
michael@0 | 4703 | """ |
michael@0 | 4704 | NonAnyType : MOZMAP LT Type GT Null |
michael@0 | 4705 | """ |
michael@0 | 4706 | innerType = p[3] |
michael@0 | 4707 | type = IDLMozMapType(self.getLocation(p, 1), innerType) |
michael@0 | 4708 | if p[5]: |
michael@0 | 4709 | type = IDLNullableType(self.getLocation(p, 5), type) |
michael@0 | 4710 | p[0] = type |
michael@0 | 4711 | |
michael@0 | 4712 | def p_NonAnyTypeScopedName(self, p): |
michael@0 | 4713 | """ |
michael@0 | 4714 | NonAnyType : ScopedName TypeSuffix |
michael@0 | 4715 | """ |
michael@0 | 4716 | assert isinstance(p[1], IDLUnresolvedIdentifier) |
michael@0 | 4717 | |
michael@0 | 4718 | type = None |
michael@0 | 4719 | |
michael@0 | 4720 | try: |
michael@0 | 4721 | if self.globalScope()._lookupIdentifier(p[1]): |
michael@0 | 4722 | obj = self.globalScope()._lookupIdentifier(p[1]) |
michael@0 | 4723 | if obj.isType(): |
michael@0 | 4724 | type = obj |
michael@0 | 4725 | else: |
michael@0 | 4726 | type = IDLWrapperType(self.getLocation(p, 1), p[1]) |
michael@0 | 4727 | p[0] = self.handleModifiers(type, p[2]) |
michael@0 | 4728 | return |
michael@0 | 4729 | except: |
michael@0 | 4730 | pass |
michael@0 | 4731 | |
michael@0 | 4732 | type = IDLUnresolvedType(self.getLocation(p, 1), p[1]) |
michael@0 | 4733 | p[0] = self.handleModifiers(type, p[2]) |
michael@0 | 4734 | |
michael@0 | 4735 | def p_NonAnyTypeDate(self, p): |
michael@0 | 4736 | """ |
michael@0 | 4737 | NonAnyType : DATE TypeSuffix |
michael@0 | 4738 | """ |
michael@0 | 4739 | p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.date], |
michael@0 | 4740 | p[2]) |
michael@0 | 4741 | |
michael@0 | 4742 | def p_ConstType(self, p): |
michael@0 | 4743 | """ |
michael@0 | 4744 | ConstType : PrimitiveOrStringType Null |
michael@0 | 4745 | """ |
michael@0 | 4746 | type = BuiltinTypes[p[1]] |
michael@0 | 4747 | if p[2]: |
michael@0 | 4748 | type = IDLNullableType(self.getLocation(p, 1), type) |
michael@0 | 4749 | p[0] = type |
michael@0 | 4750 | |
michael@0 | 4751 | def p_ConstTypeIdentifier(self, p): |
michael@0 | 4752 | """ |
michael@0 | 4753 | ConstType : IDENTIFIER Null |
michael@0 | 4754 | """ |
michael@0 | 4755 | identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) |
michael@0 | 4756 | |
michael@0 | 4757 | type = IDLUnresolvedType(self.getLocation(p, 1), identifier) |
michael@0 | 4758 | if p[2]: |
michael@0 | 4759 | type = IDLNullableType(self.getLocation(p, 1), type) |
michael@0 | 4760 | p[0] = type |
michael@0 | 4761 | |
michael@0 | 4762 | def p_PrimitiveOrStringTypeUint(self, p): |
michael@0 | 4763 | """ |
michael@0 | 4764 | PrimitiveOrStringType : UnsignedIntegerType |
michael@0 | 4765 | """ |
michael@0 | 4766 | p[0] = p[1] |
michael@0 | 4767 | |
michael@0 | 4768 | def p_PrimitiveOrStringTypeBoolean(self, p): |
michael@0 | 4769 | """ |
michael@0 | 4770 | PrimitiveOrStringType : BOOLEAN |
michael@0 | 4771 | """ |
michael@0 | 4772 | p[0] = IDLBuiltinType.Types.boolean |
michael@0 | 4773 | |
michael@0 | 4774 | def p_PrimitiveOrStringTypeByte(self, p): |
michael@0 | 4775 | """ |
michael@0 | 4776 | PrimitiveOrStringType : BYTE |
michael@0 | 4777 | """ |
michael@0 | 4778 | p[0] = IDLBuiltinType.Types.byte |
michael@0 | 4779 | |
michael@0 | 4780 | def p_PrimitiveOrStringTypeOctet(self, p): |
michael@0 | 4781 | """ |
michael@0 | 4782 | PrimitiveOrStringType : OCTET |
michael@0 | 4783 | """ |
michael@0 | 4784 | p[0] = IDLBuiltinType.Types.octet |
michael@0 | 4785 | |
michael@0 | 4786 | def p_PrimitiveOrStringTypeFloat(self, p): |
michael@0 | 4787 | """ |
michael@0 | 4788 | PrimitiveOrStringType : FLOAT |
michael@0 | 4789 | """ |
michael@0 | 4790 | p[0] = IDLBuiltinType.Types.float |
michael@0 | 4791 | |
michael@0 | 4792 | def p_PrimitiveOrStringTypeUnrestictedFloat(self, p): |
michael@0 | 4793 | """ |
michael@0 | 4794 | PrimitiveOrStringType : UNRESTRICTED FLOAT |
michael@0 | 4795 | """ |
michael@0 | 4796 | p[0] = IDLBuiltinType.Types.unrestricted_float |
michael@0 | 4797 | |
michael@0 | 4798 | def p_PrimitiveOrStringTypeDouble(self, p): |
michael@0 | 4799 | """ |
michael@0 | 4800 | PrimitiveOrStringType : DOUBLE |
michael@0 | 4801 | """ |
michael@0 | 4802 | p[0] = IDLBuiltinType.Types.double |
michael@0 | 4803 | |
michael@0 | 4804 | def p_PrimitiveOrStringTypeUnrestictedDouble(self, p): |
michael@0 | 4805 | """ |
michael@0 | 4806 | PrimitiveOrStringType : UNRESTRICTED DOUBLE |
michael@0 | 4807 | """ |
michael@0 | 4808 | p[0] = IDLBuiltinType.Types.unrestricted_double |
michael@0 | 4809 | |
michael@0 | 4810 | def p_PrimitiveOrStringTypeDOMString(self, p): |
michael@0 | 4811 | """ |
michael@0 | 4812 | PrimitiveOrStringType : DOMSTRING |
michael@0 | 4813 | """ |
michael@0 | 4814 | p[0] = IDLBuiltinType.Types.domstring |
michael@0 | 4815 | |
michael@0 | 4816 | def p_PrimitiveOrStringTypeBytestring(self, p): |
michael@0 | 4817 | """ |
michael@0 | 4818 | PrimitiveOrStringType : BYTESTRING |
michael@0 | 4819 | """ |
michael@0 | 4820 | p[0] = IDLBuiltinType.Types.bytestring |
michael@0 | 4821 | |
michael@0 | 4822 | def p_UnsignedIntegerTypeUnsigned(self, p): |
michael@0 | 4823 | """ |
michael@0 | 4824 | UnsignedIntegerType : UNSIGNED IntegerType |
michael@0 | 4825 | """ |
michael@0 | 4826 | p[0] = p[2] + 1 # Adding one to a given signed integer type |
michael@0 | 4827 | # gets you the unsigned type. |
michael@0 | 4828 | |
michael@0 | 4829 | def p_UnsignedIntegerType(self, p): |
michael@0 | 4830 | """ |
michael@0 | 4831 | UnsignedIntegerType : IntegerType |
michael@0 | 4832 | """ |
michael@0 | 4833 | p[0] = p[1] |
michael@0 | 4834 | |
michael@0 | 4835 | def p_IntegerTypeShort(self, p): |
michael@0 | 4836 | """ |
michael@0 | 4837 | IntegerType : SHORT |
michael@0 | 4838 | """ |
michael@0 | 4839 | p[0] = IDLBuiltinType.Types.short |
michael@0 | 4840 | |
michael@0 | 4841 | def p_IntegerTypeLong(self, p): |
michael@0 | 4842 | """ |
michael@0 | 4843 | IntegerType : LONG OptionalLong |
michael@0 | 4844 | """ |
michael@0 | 4845 | if p[2]: |
michael@0 | 4846 | p[0] = IDLBuiltinType.Types.long_long |
michael@0 | 4847 | else: |
michael@0 | 4848 | p[0] = IDLBuiltinType.Types.long |
michael@0 | 4849 | |
michael@0 | 4850 | def p_OptionalLong(self, p): |
michael@0 | 4851 | """ |
michael@0 | 4852 | OptionalLong : LONG |
michael@0 | 4853 | """ |
michael@0 | 4854 | p[0] = True |
michael@0 | 4855 | |
michael@0 | 4856 | def p_OptionalLongEmpty(self, p): |
michael@0 | 4857 | """ |
michael@0 | 4858 | OptionalLong : |
michael@0 | 4859 | """ |
michael@0 | 4860 | p[0] = False |
michael@0 | 4861 | |
michael@0 | 4862 | def p_TypeSuffixBrackets(self, p): |
michael@0 | 4863 | """ |
michael@0 | 4864 | TypeSuffix : LBRACKET RBRACKET TypeSuffix |
michael@0 | 4865 | """ |
michael@0 | 4866 | p[0] = [(IDLMethod.TypeSuffixModifier.Brackets, self.getLocation(p, 1))] |
michael@0 | 4867 | p[0].extend(p[3]) |
michael@0 | 4868 | |
michael@0 | 4869 | def p_TypeSuffixQMark(self, p): |
michael@0 | 4870 | """ |
michael@0 | 4871 | TypeSuffix : QUESTIONMARK TypeSuffixStartingWithArray |
michael@0 | 4872 | """ |
michael@0 | 4873 | p[0] = [(IDLMethod.TypeSuffixModifier.QMark, self.getLocation(p, 1))] |
michael@0 | 4874 | p[0].extend(p[2]) |
michael@0 | 4875 | |
michael@0 | 4876 | def p_TypeSuffixEmpty(self, p): |
michael@0 | 4877 | """ |
michael@0 | 4878 | TypeSuffix : |
michael@0 | 4879 | """ |
michael@0 | 4880 | p[0] = [] |
michael@0 | 4881 | |
michael@0 | 4882 | def p_TypeSuffixStartingWithArray(self, p): |
michael@0 | 4883 | """ |
michael@0 | 4884 | TypeSuffixStartingWithArray : LBRACKET RBRACKET TypeSuffix |
michael@0 | 4885 | """ |
michael@0 | 4886 | p[0] = [(IDLMethod.TypeSuffixModifier.Brackets, self.getLocation(p, 1))] |
michael@0 | 4887 | p[0].extend(p[3]) |
michael@0 | 4888 | |
michael@0 | 4889 | def p_TypeSuffixStartingWithArrayEmpty(self, p): |
michael@0 | 4890 | """ |
michael@0 | 4891 | TypeSuffixStartingWithArray : |
michael@0 | 4892 | """ |
michael@0 | 4893 | p[0] = [] |
michael@0 | 4894 | |
michael@0 | 4895 | def p_Null(self, p): |
michael@0 | 4896 | """ |
michael@0 | 4897 | Null : QUESTIONMARK |
michael@0 | 4898 | | |
michael@0 | 4899 | """ |
michael@0 | 4900 | if len(p) > 1: |
michael@0 | 4901 | p[0] = True |
michael@0 | 4902 | else: |
michael@0 | 4903 | p[0] = False |
michael@0 | 4904 | |
michael@0 | 4905 | def p_ReturnTypeType(self, p): |
michael@0 | 4906 | """ |
michael@0 | 4907 | ReturnType : Type |
michael@0 | 4908 | """ |
michael@0 | 4909 | p[0] = p[1] |
michael@0 | 4910 | |
michael@0 | 4911 | def p_ReturnTypeVoid(self, p): |
michael@0 | 4912 | """ |
michael@0 | 4913 | ReturnType : VOID |
michael@0 | 4914 | """ |
michael@0 | 4915 | p[0] = BuiltinTypes[IDLBuiltinType.Types.void] |
michael@0 | 4916 | |
michael@0 | 4917 | def p_ScopedName(self, p): |
michael@0 | 4918 | """ |
michael@0 | 4919 | ScopedName : AbsoluteScopedName |
michael@0 | 4920 | | RelativeScopedName |
michael@0 | 4921 | """ |
michael@0 | 4922 | p[0] = p[1] |
michael@0 | 4923 | |
michael@0 | 4924 | def p_AbsoluteScopedName(self, p): |
michael@0 | 4925 | """ |
michael@0 | 4926 | AbsoluteScopedName : SCOPE IDENTIFIER ScopedNameParts |
michael@0 | 4927 | """ |
michael@0 | 4928 | assert False |
michael@0 | 4929 | pass |
michael@0 | 4930 | |
michael@0 | 4931 | def p_RelativeScopedName(self, p): |
michael@0 | 4932 | """ |
michael@0 | 4933 | RelativeScopedName : IDENTIFIER ScopedNameParts |
michael@0 | 4934 | """ |
michael@0 | 4935 | assert not p[2] # Not implemented! |
michael@0 | 4936 | |
michael@0 | 4937 | p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) |
michael@0 | 4938 | |
michael@0 | 4939 | def p_ScopedNameParts(self, p): |
michael@0 | 4940 | """ |
michael@0 | 4941 | ScopedNameParts : SCOPE IDENTIFIER ScopedNameParts |
michael@0 | 4942 | """ |
michael@0 | 4943 | assert False |
michael@0 | 4944 | pass |
michael@0 | 4945 | |
michael@0 | 4946 | def p_ScopedNamePartsEmpty(self, p): |
michael@0 | 4947 | """ |
michael@0 | 4948 | ScopedNameParts : |
michael@0 | 4949 | """ |
michael@0 | 4950 | p[0] = None |
michael@0 | 4951 | |
michael@0 | 4952 | def p_ExtendedAttributeNoArgs(self, p): |
michael@0 | 4953 | """ |
michael@0 | 4954 | ExtendedAttributeNoArgs : IDENTIFIER |
michael@0 | 4955 | """ |
michael@0 | 4956 | p[0] = (p[1],) |
michael@0 | 4957 | |
michael@0 | 4958 | def p_ExtendedAttributeArgList(self, p): |
michael@0 | 4959 | """ |
michael@0 | 4960 | ExtendedAttributeArgList : IDENTIFIER LPAREN ArgumentList RPAREN |
michael@0 | 4961 | """ |
michael@0 | 4962 | p[0] = (p[1], p[3]) |
michael@0 | 4963 | |
michael@0 | 4964 | def p_ExtendedAttributeIdent(self, p): |
michael@0 | 4965 | """ |
michael@0 | 4966 | ExtendedAttributeIdent : IDENTIFIER EQUALS STRING |
michael@0 | 4967 | | IDENTIFIER EQUALS IDENTIFIER |
michael@0 | 4968 | """ |
michael@0 | 4969 | p[0] = (p[1], p[3]) |
michael@0 | 4970 | |
michael@0 | 4971 | def p_ExtendedAttributeNamedArgList(self, p): |
michael@0 | 4972 | """ |
michael@0 | 4973 | ExtendedAttributeNamedArgList : IDENTIFIER EQUALS IDENTIFIER LPAREN ArgumentList RPAREN |
michael@0 | 4974 | """ |
michael@0 | 4975 | p[0] = (p[1], p[3], p[5]) |
michael@0 | 4976 | |
michael@0 | 4977 | def p_error(self, p): |
michael@0 | 4978 | if not p: |
michael@0 | 4979 | raise WebIDLError("Syntax Error at end of file. Possibly due to missing semicolon(;), braces(}) or both", |
michael@0 | 4980 | [self._filename]) |
michael@0 | 4981 | else: |
michael@0 | 4982 | raise WebIDLError("invalid syntax", [Location(self.lexer, p.lineno, p.lexpos, self._filename)]) |
michael@0 | 4983 | |
michael@0 | 4984 | def __init__(self, outputdir='', lexer=None): |
michael@0 | 4985 | Tokenizer.__init__(self, outputdir, lexer) |
michael@0 | 4986 | self.parser = yacc.yacc(module=self, |
michael@0 | 4987 | outputdir=outputdir, |
michael@0 | 4988 | tabmodule='webidlyacc', |
michael@0 | 4989 | errorlog=yacc.NullLogger(), |
michael@0 | 4990 | picklefile='WebIDLGrammar.pkl') |
michael@0 | 4991 | self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None) |
michael@0 | 4992 | self._installBuiltins(self._globalScope) |
michael@0 | 4993 | self._productions = [] |
michael@0 | 4994 | |
michael@0 | 4995 | self._filename = "<builtin>" |
michael@0 | 4996 | self.lexer.input(Parser._builtins) |
michael@0 | 4997 | self._filename = None |
michael@0 | 4998 | |
michael@0 | 4999 | self.parser.parse(lexer=self.lexer,tracking=True) |
michael@0 | 5000 | |
michael@0 | 5001 | def _installBuiltins(self, scope): |
michael@0 | 5002 | assert isinstance(scope, IDLScope) |
michael@0 | 5003 | |
michael@0 | 5004 | # xrange omits the last value. |
michael@0 | 5005 | for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1): |
michael@0 | 5006 | builtin = BuiltinTypes[x] |
michael@0 | 5007 | name = builtin.name |
michael@0 | 5008 | |
michael@0 | 5009 | typedef = IDLTypedefType(BuiltinLocation("<builtin type>"), builtin, name) |
michael@0 | 5010 | typedef.resolve(scope) |
michael@0 | 5011 | |
michael@0 | 5012 | @ staticmethod |
michael@0 | 5013 | def handleModifiers(type, modifiers): |
michael@0 | 5014 | for (modifier, modifierLocation) in modifiers: |
michael@0 | 5015 | assert modifier == IDLMethod.TypeSuffixModifier.QMark or \ |
michael@0 | 5016 | modifier == IDLMethod.TypeSuffixModifier.Brackets |
michael@0 | 5017 | |
michael@0 | 5018 | if modifier == IDLMethod.TypeSuffixModifier.QMark: |
michael@0 | 5019 | type = IDLNullableType(modifierLocation, type) |
michael@0 | 5020 | elif modifier == IDLMethod.TypeSuffixModifier.Brackets: |
michael@0 | 5021 | type = IDLArrayType(modifierLocation, type) |
michael@0 | 5022 | |
michael@0 | 5023 | return type |
michael@0 | 5024 | |
michael@0 | 5025 | def parse(self, t, filename=None): |
michael@0 | 5026 | self.lexer.input(t) |
michael@0 | 5027 | |
michael@0 | 5028 | #for tok in iter(self.lexer.token, None): |
michael@0 | 5029 | # print tok |
michael@0 | 5030 | |
michael@0 | 5031 | self._filename = filename |
michael@0 | 5032 | self._productions.extend(self.parser.parse(lexer=self.lexer,tracking=True)) |
michael@0 | 5033 | self._filename = None |
michael@0 | 5034 | |
michael@0 | 5035 | def finish(self): |
michael@0 | 5036 | # First, finish all the IDLImplementsStatements. In particular, we |
michael@0 | 5037 | # have to make sure we do those before we do the IDLInterfaces. |
michael@0 | 5038 | # XXX khuey hates this bit and wants to nuke it from orbit. |
michael@0 | 5039 | implementsStatements = [ p for p in self._productions if |
michael@0 | 5040 | isinstance(p, IDLImplementsStatement)] |
michael@0 | 5041 | otherStatements = [ p for p in self._productions if |
michael@0 | 5042 | not isinstance(p, IDLImplementsStatement)] |
michael@0 | 5043 | for production in implementsStatements: |
michael@0 | 5044 | production.finish(self.globalScope()) |
michael@0 | 5045 | for production in otherStatements: |
michael@0 | 5046 | production.finish(self.globalScope()) |
michael@0 | 5047 | |
michael@0 | 5048 | # Do any post-finish validation we need to do |
michael@0 | 5049 | for production in self._productions: |
michael@0 | 5050 | production.validate() |
michael@0 | 5051 | |
michael@0 | 5052 | # De-duplicate self._productions, without modifying its order. |
michael@0 | 5053 | seen = set() |
michael@0 | 5054 | result = [] |
michael@0 | 5055 | for p in self._productions: |
michael@0 | 5056 | if p not in seen: |
michael@0 | 5057 | seen.add(p) |
michael@0 | 5058 | result.append(p) |
michael@0 | 5059 | return result |
michael@0 | 5060 | |
michael@0 | 5061 | def reset(self): |
michael@0 | 5062 | return Parser(lexer=self.lexer) |
michael@0 | 5063 | |
michael@0 | 5064 | # Builtin IDL defined by WebIDL |
michael@0 | 5065 | _builtins = """ |
michael@0 | 5066 | typedef unsigned long long DOMTimeStamp; |
michael@0 | 5067 | """ |
michael@0 | 5068 | |
michael@0 | 5069 | def main(): |
michael@0 | 5070 | # Parse arguments. |
michael@0 | 5071 | from optparse import OptionParser |
michael@0 | 5072 | usageString = "usage: %prog [options] files" |
michael@0 | 5073 | o = OptionParser(usage=usageString) |
michael@0 | 5074 | o.add_option("--cachedir", dest='cachedir', default=None, |
michael@0 | 5075 | help="Directory in which to cache lex/parse tables.") |
michael@0 | 5076 | o.add_option("--verbose-errors", action='store_true', default=False, |
michael@0 | 5077 | help="When an error happens, display the Python traceback.") |
michael@0 | 5078 | (options, args) = o.parse_args() |
michael@0 | 5079 | |
michael@0 | 5080 | if len(args) < 1: |
michael@0 | 5081 | o.error(usageString) |
michael@0 | 5082 | |
michael@0 | 5083 | fileList = args |
michael@0 | 5084 | baseDir = os.getcwd() |
michael@0 | 5085 | |
michael@0 | 5086 | # Parse the WebIDL. |
michael@0 | 5087 | parser = Parser(options.cachedir) |
michael@0 | 5088 | try: |
michael@0 | 5089 | for filename in fileList: |
michael@0 | 5090 | fullPath = os.path.normpath(os.path.join(baseDir, filename)) |
michael@0 | 5091 | f = open(fullPath, 'rb') |
michael@0 | 5092 | lines = f.readlines() |
michael@0 | 5093 | f.close() |
michael@0 | 5094 | print fullPath |
michael@0 | 5095 | parser.parse(''.join(lines), fullPath) |
michael@0 | 5096 | parser.finish() |
michael@0 | 5097 | except WebIDLError, e: |
michael@0 | 5098 | if options.verbose_errors: |
michael@0 | 5099 | traceback.print_exc() |
michael@0 | 5100 | else: |
michael@0 | 5101 | print e |
michael@0 | 5102 | |
michael@0 | 5103 | if __name__ == '__main__': |
michael@0 | 5104 | main() |