зеркало из https://github.com/mozilla/pjs.git
Bug 741125: Update WebIDL parser.
This commit is contained in:
Родитель
960820e223
Коммит
70daea2117
31
client.py
31
client.py
|
@ -7,6 +7,9 @@ NSS_DIRS = (('dbm', 'mozilla/dbm'),
|
|||
('security/dbm', 'mozilla/security/dbm'))
|
||||
NSSCKBI_DIRS = (('security/nss/lib/ckfw/builtins', 'mozilla/security/nss/lib/ckfw/builtins'),)
|
||||
LIBFFI_DIRS = (('js/ctypes/libffi', 'libffi'),)
|
||||
WEBIDLPARSER_DIR = 'dom/bindings/parser'
|
||||
WEBIDLPARSER_REPO = 'https://hg.mozilla.org/users/khuey_mozilla.com/webidl-parser'
|
||||
WEBIDLPARSER_EXCLUSIONS = ['.hgignore', '.gitignore', '.hg', 'ply']
|
||||
|
||||
CVSROOT_MOZILLA = ':pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot'
|
||||
CVSROOT_LIBFFI = ':pserver:anoncvs@sources.redhat.com:/cvs/libffi'
|
||||
|
@ -15,6 +18,7 @@ import os
|
|||
import sys
|
||||
import datetime
|
||||
import shutil
|
||||
import glob
|
||||
from optparse import OptionParser
|
||||
from subprocess import check_call
|
||||
|
||||
|
@ -30,7 +34,6 @@ def do_hg_pull(dir, repository, hg):
|
|||
fulldir = os.path.join(topsrcdir, dir)
|
||||
# clone if the dir doesn't exist, pull if it does
|
||||
if not os.path.exists(fulldir):
|
||||
fulldir = os.path.join(topsrcdir, dir)
|
||||
check_call_noisy([hg, 'clone', repository, fulldir])
|
||||
else:
|
||||
cmd = [hg, 'pull', '-u', '-R', fulldir]
|
||||
|
@ -40,6 +43,25 @@ def do_hg_pull(dir, repository, hg):
|
|||
check_call([hg, 'parent', '-R', fulldir,
|
||||
'--template=Updated to revision {node}.\n'])
|
||||
|
||||
def do_hg_replace(dir, repository, tag, exclusions, hg):
|
||||
"""
|
||||
Replace the contents of dir with the contents of repository, except for
|
||||
files matching exclusions.
|
||||
"""
|
||||
fulldir = os.path.join(topsrcdir, dir)
|
||||
if os.path.exists(fulldir):
|
||||
shutil.rmtree(fulldir)
|
||||
|
||||
assert not os.path.exists(fulldir)
|
||||
check_call_noisy([hg, 'clone', '-u', tag, repository, fulldir])
|
||||
|
||||
for thing in exclusions:
|
||||
for excluded in glob.iglob(os.path.join(fulldir, thing)):
|
||||
if os.path.isdir(excluded):
|
||||
shutil.rmtree(excluded)
|
||||
else:
|
||||
os.remove(excluded)
|
||||
|
||||
def do_cvs_export(modules, tag, cvsroot, cvs):
|
||||
"""Check out a CVS directory without CVS metadata, using "export"
|
||||
modules is a list of directories to check out and the corresponding
|
||||
|
@ -60,7 +82,7 @@ def do_cvs_export(modules, tag, cvsroot, cvs):
|
|||
cwd=os.path.join(topsrcdir, parent))
|
||||
print "CVS export end: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||
|
||||
o = OptionParser(usage="client.py [options] update_nspr tagname | update_nss tagname | update_libffi tagname")
|
||||
o = OptionParser(usage="client.py [options] update_nspr tagname | update_nss tagname | update_libffi tagname | update_webidlparser tagname")
|
||||
o.add_option("--skip-mozilla", dest="skip_mozilla",
|
||||
action="store_true", default=False,
|
||||
help="Obsolete")
|
||||
|
@ -69,6 +91,8 @@ o.add_option("--cvs", dest="cvs", default=os.environ.get('CVS', 'cvs'),
|
|||
help="The location of the cvs binary")
|
||||
o.add_option("--cvsroot", dest="cvsroot",
|
||||
help="The CVSROOT (default for mozilla checkouts: %s)" % CVSROOT_MOZILLA)
|
||||
o.add_option("--hg", dest="hg", default=os.environ.get('HG', 'hg'),
|
||||
help="The location of the hg binary")
|
||||
|
||||
try:
|
||||
options, args = o.parse_args()
|
||||
|
@ -104,6 +128,9 @@ elif action in ('update_libffi'):
|
|||
if not options.cvsroot:
|
||||
options.cvsroot = CVSROOT_LIBFFI
|
||||
do_cvs_export(LIBFFI_DIRS, tag, options.cvsroot, options.cvs)
|
||||
elif action in ('update_webidlparser'):
|
||||
tag, = args[1:]
|
||||
do_hg_replace(WEBIDLPARSER_DIR, WEBIDLPARSER_REPO, tag, WEBIDLPARSER_EXCLUSIONS, options.hg)
|
||||
else:
|
||||
o.print_help()
|
||||
sys.exit(2)
|
||||
|
|
|
@ -75,7 +75,7 @@ bindinggen_dependencies := \
|
|||
$(binding_header_files): %Binding.h: $(bindinggen_dependencies) \
|
||||
$(webidl_base)/%.webidl \
|
||||
$(NULL)
|
||||
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||
$(PLY_INCLUDE) -I$(srcdir)/parser \
|
||||
$(srcdir)/BindingGen.py $(ACCESSOR_OPT) header \
|
||||
$(srcdir)/Bindings.conf $*Binding \
|
||||
|
@ -84,7 +84,7 @@ $(binding_header_files): %Binding.h: $(bindinggen_dependencies) \
|
|||
$(binding_cpp_files): %Binding.cpp: $(bindinggen_dependencies) \
|
||||
$(webidl_base)/%.webidl \
|
||||
$(NULL)
|
||||
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||
$(PLY_INCLUDE) -I$(srcdir)/parser \
|
||||
$(srcdir)/BindingGen.py $(ACCESSOR_OPT) cpp \
|
||||
$(srcdir)/Bindings.conf $*Binding \
|
||||
|
@ -109,7 +109,7 @@ $(CACHE_DIR)/.done:
|
|||
|
||||
ParserResults.pkl: $(globalgen_dependencies) \
|
||||
$(addprefix $(webidl_base)/, $(webidl_files))
|
||||
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||
$(PLY_INCLUDE) -I$(srcdir)/parser \
|
||||
$(srcdir)/GlobalGen.py $(ACCESSOR_OPT) $(srcdir)/Bindings.conf $(webidl_base) \
|
||||
--cachedir=$(CACHE_DIR) \
|
||||
|
|
|
@ -69,14 +69,16 @@ def parseInt(literal):
|
|||
# Magic for creating enums
|
||||
def M_add_class_attribs(attribs):
|
||||
def foo(name, bases, dict_):
|
||||
for v, k in attribs:
|
||||
for v, k in enumerate(attribs):
|
||||
dict_[k] = v
|
||||
assert 'length' not in dict_
|
||||
dict_['length'] = len(attribs)
|
||||
return type(name, bases, dict_)
|
||||
return foo
|
||||
|
||||
def enum(*names):
|
||||
class Foo(object):
|
||||
__metaclass__ = M_add_class_attribs(enumerate(names))
|
||||
__metaclass__ = M_add_class_attribs(names)
|
||||
def __setattr__(self, name, value): # this makes it read-only
|
||||
raise NotImplementedError
|
||||
return Foo()
|
||||
|
@ -93,9 +95,8 @@ class WebIDLError(Exception):
|
|||
self.location)
|
||||
|
||||
class Location(object):
|
||||
_line = None
|
||||
|
||||
def __init__(self, lexer, lineno, lexpos, filename):
|
||||
self._line = None
|
||||
self._lineno = lineno
|
||||
self._lexpos = lexpos
|
||||
self._lexdata = lexer.lexdata
|
||||
|
@ -105,36 +106,47 @@ class Location(object):
|
|||
return self._lexpos == other._lexpos and \
|
||||
self._file == other._file
|
||||
|
||||
def filename(self):
|
||||
return self._file
|
||||
|
||||
def resolve(self):
|
||||
if self._line:
|
||||
return
|
||||
|
||||
startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1
|
||||
endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80)
|
||||
self._line = self._lexdata[startofline:endofline]
|
||||
if endofline != -1:
|
||||
self._line = self._lexdata[startofline:endofline]
|
||||
else:
|
||||
self._line = self._lexdata[startofline:]
|
||||
self._colno = self._lexpos - startofline
|
||||
|
||||
def pointerline(self):
|
||||
def i():
|
||||
for i in xrange(0, self._colno):
|
||||
yield " "
|
||||
yield "^"
|
||||
|
||||
return "".join(i())
|
||||
|
||||
def get(self):
|
||||
self.resolve()
|
||||
return "%s line %s:%s" % (self._file, self._lineno, self._colno)
|
||||
|
||||
def _pointerline(self):
|
||||
return " " * self._colno + "^"
|
||||
|
||||
def __str__(self):
|
||||
self.resolve()
|
||||
return "%s line %s:%s\n%s\n%s" % (self._file, self._lineno, self._colno,
|
||||
self._line, self.pointerline())
|
||||
self._line, self._pointerline())
|
||||
|
||||
class BuiltinLocation(object):
|
||||
def __init__(self, text):
|
||||
self.msg = text
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, BuiltinLocation) and \
|
||||
self.msg == other.msg
|
||||
|
||||
def filename(self):
|
||||
return '<builtin>'
|
||||
|
||||
def resolve(self):
|
||||
pass
|
||||
|
||||
def get(self):
|
||||
return self.msg
|
||||
|
||||
|
@ -150,7 +162,7 @@ class IDLObject(object):
|
|||
self.userData = dict()
|
||||
|
||||
def filename(self):
|
||||
return self.location._file
|
||||
return self.location.filename()
|
||||
|
||||
def isInterface(self):
|
||||
return False
|
||||
|
@ -198,6 +210,11 @@ class IDLScope(IDLObject):
|
|||
return "::"
|
||||
|
||||
def ensureUnique(self, identifier, object):
|
||||
"""
|
||||
Ensure that there is at most one 'identifier' in scope ('self').
|
||||
Note that object can be None. This occurs if we end up here for an
|
||||
interface type we haven't seen yet.
|
||||
"""
|
||||
assert isinstance(identifier, IDLUnresolvedIdentifier)
|
||||
assert not object or isinstance(object, IDLObjectWithIdentifier)
|
||||
assert not object or object.identifier == identifier
|
||||
|
@ -300,6 +317,9 @@ class IDLUnresolvedIdentifier(IDLObject):
|
|||
object.identifier = identifier
|
||||
return identifier
|
||||
|
||||
def finish(self):
|
||||
assert False # Should replace with a resolved identifier first.
|
||||
|
||||
class IDLObjectWithIdentifier(IDLObject):
|
||||
def __init__(self, location, parentScope, identifier):
|
||||
IDLObject.__init__(self, location)
|
||||
|
@ -368,9 +388,8 @@ class IDLInterface(IDLObjectWithScope):
|
|||
|
||||
self.parent = parent
|
||||
self._callback = False
|
||||
|
||||
self._finished = False
|
||||
self.members = list(members) # clone the list
|
||||
assert iter(self.members) # Assert it's iterable
|
||||
|
||||
IDLObjectWithScope.__init__(self, location, parentScope, name)
|
||||
|
||||
|
@ -404,7 +423,7 @@ class IDLInterface(IDLObjectWithScope):
|
|||
return retval
|
||||
|
||||
def finish(self, scope):
|
||||
if hasattr(self, "_finished"):
|
||||
if self._finished:
|
||||
return
|
||||
|
||||
self._finished = True
|
||||
|
@ -416,7 +435,6 @@ class IDLInterface(IDLObjectWithScope):
|
|||
self.parent = parent
|
||||
|
||||
assert iter(self.members)
|
||||
members = None
|
||||
|
||||
if self.parent:
|
||||
self.parent.finish(scope)
|
||||
|
@ -427,19 +445,6 @@ class IDLInterface(IDLObjectWithScope):
|
|||
else:
|
||||
members = list(self.members)
|
||||
|
||||
SpecialType = enum(
|
||||
'NamedGetter',
|
||||
'NamedSetter',
|
||||
'NamedCreator',
|
||||
'NamedDeleter',
|
||||
'IndexedGetter',
|
||||
'IndexedSetter',
|
||||
'IndexedCreator',
|
||||
'IndexedDeleter'
|
||||
)
|
||||
|
||||
specialMembersSeen = [False for i in range(8)]
|
||||
|
||||
def memberNotOnParentChain(member, iface):
|
||||
assert iface
|
||||
|
||||
|
@ -451,59 +456,39 @@ class IDLInterface(IDLObjectWithScope):
|
|||
return False
|
||||
return memberNotOnParentChain(member, iface.parent)
|
||||
|
||||
# Ensure that there's at most one of each {named,indexed}
|
||||
# {getter,setter,creator,deleter}.
|
||||
specialMembersSeen = set()
|
||||
for member in members:
|
||||
if memberNotOnParentChain(member, self):
|
||||
member.resolve(self)
|
||||
|
||||
if member.tag == IDLInterfaceMember.Tags.Method:
|
||||
if member.isGetter():
|
||||
if member.isNamed():
|
||||
if specialMembersSeen[SpecialType.NamedGetter]:
|
||||
raise WebIDLError("Multiple named getters on %s" % (self),
|
||||
self.location)
|
||||
specialMembersSeen[SpecialType.NamedGetter] = True
|
||||
else:
|
||||
assert member.isIndexed()
|
||||
if specialMembersSeen[SpecialType.IndexedGetter]:
|
||||
raise WebIDLError("Multiple indexed getters on %s" % (self),
|
||||
self.location)
|
||||
specialMembersSeen[SpecialType.IndexedGetter] = True
|
||||
if member.isSetter():
|
||||
if member.isNamed():
|
||||
if specialMembersSeen[SpecialType.NamedSetter]:
|
||||
raise WebIDLError("Multiple named setters on %s" % (self),
|
||||
self.location)
|
||||
specialMembersSeen[SpecialType.NamedSetter] = True
|
||||
else:
|
||||
assert member.isIndexed()
|
||||
if specialMembersSeen[SpecialType.IndexedSetter]:
|
||||
raise WebIDLError("Multiple indexed setters on %s" % (self),
|
||||
self.location)
|
||||
specialMembersSeen[SpecialType.IndexedSetter] = True
|
||||
if member.isCreator():
|
||||
if member.isNamed():
|
||||
if specialMembersSeen[SpecialType.NamedCreator]:
|
||||
raise WebIDLError("Multiple named creators on %s" % (self),
|
||||
self.location)
|
||||
specialMembersSeen[SpecialType.NamedCreator] = True
|
||||
else:
|
||||
assert member.isIndexed()
|
||||
if specialMembersSeen[SpecialType.IndexedCreator]:
|
||||
raise WebIDLError("Multiple indexed creators on %s" % (self),
|
||||
self.location)
|
||||
specialMembersSeen[SpecialType.IndexedCreator] = True
|
||||
if member.isDeleter():
|
||||
if member.isNamed():
|
||||
if specialMembersSeen[SpecialType.NamedDeleter]:
|
||||
raise WebIDLError("Multiple named deleters on %s" % (self),
|
||||
self.location)
|
||||
specialMembersSeen[SpecialType.NamedDeleter] = True
|
||||
else:
|
||||
assert member.isIndexed()
|
||||
if specialMembersSeen[SpecialType.IndexedDeleter]:
|
||||
raise WebIDLError("Multiple indexed Deleters on %s" % (self),
|
||||
self.location)
|
||||
specialMembersSeen[SpecialType.IndexedDeleter] = True
|
||||
|
||||
if member.tag != IDLInterfaceMember.Tags.Method:
|
||||
continue
|
||||
|
||||
if member.isGetter():
|
||||
memberType = "getters"
|
||||
elif member.isSetter():
|
||||
memberType = "setters"
|
||||
elif member.isCreator():
|
||||
memberType = "creators"
|
||||
elif member.isDeleter():
|
||||
memberType = "deleters"
|
||||
else:
|
||||
continue
|
||||
|
||||
if member.isNamed():
|
||||
memberType = "named " + memberType
|
||||
elif member.isIndexed():
|
||||
memberType = "indexed " + memberType
|
||||
else:
|
||||
continue
|
||||
|
||||
if memberType in specialMembersSeen:
|
||||
raise WebIDLError("Multiple " + memberType + " on %s" % (self),
|
||||
self.location)
|
||||
|
||||
specialMembersSeen.add(memberType)
|
||||
|
||||
for member in self.members:
|
||||
member.finish(scope)
|
||||
|
@ -529,7 +514,7 @@ class IDLInterface(IDLObjectWithScope):
|
|||
return depth
|
||||
|
||||
def hasConstants(self):
|
||||
return reduce(lambda b, m: b or m.isConst(), self.members, False)
|
||||
return any(m.isConst() for m in self.members)
|
||||
|
||||
def hasInterfaceObject(self):
|
||||
if self.isCallback():
|
||||
|
@ -567,10 +552,7 @@ class IDLInterface(IDLObjectWithScope):
|
|||
identifier = IDLUnresolvedIdentifier(self.location, "constructor",
|
||||
allowForbidden=True)
|
||||
|
||||
method = IDLMethod(self.location, identifier, retType, args,
|
||||
False, False, False, False, False, False,
|
||||
False, False)
|
||||
|
||||
method = IDLMethod(self.location, identifier, retType, args)
|
||||
method.resolve(self)
|
||||
|
||||
self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
|
||||
|
@ -763,6 +745,12 @@ class IDLNullableType(IDLType):
|
|||
def isString(self):
|
||||
return self.inner.isString()
|
||||
|
||||
def isFloat(self):
|
||||
return self.inner.isFloat()
|
||||
|
||||
def isInteger(self):
|
||||
return self.inner.isInteger()
|
||||
|
||||
def isVoid(self):
|
||||
return False
|
||||
|
||||
|
@ -772,6 +760,9 @@ class IDLNullableType(IDLType):
|
|||
def isArray(self):
|
||||
return self.inner.isArray()
|
||||
|
||||
def isArrayBuffer(self):
|
||||
return self.inner.isArrayBuffer()
|
||||
|
||||
def isDictionary(self):
|
||||
return self.inner.isDictionary()
|
||||
|
||||
|
@ -797,7 +788,7 @@ class IDLNullableType(IDLType):
|
|||
return self
|
||||
|
||||
def unroll(self):
|
||||
return self.inner
|
||||
return self.inner.unroll()
|
||||
|
||||
def isDistinguishableFrom(self, other):
|
||||
if other.nullable():
|
||||
|
@ -835,18 +826,19 @@ class IDLSequenceType(IDLType):
|
|||
return True
|
||||
|
||||
def isArray(self):
|
||||
return self.inner.isArray()
|
||||
return False
|
||||
|
||||
def isDictionary(self):
|
||||
return self.inner.isDictionary()
|
||||
return False
|
||||
|
||||
def isInterface(self):
|
||||
return self.inner.isInterface()
|
||||
return False
|
||||
|
||||
def isEnum(self):
|
||||
return self.inner.isEnum();
|
||||
return False
|
||||
|
||||
def tag(self):
|
||||
# XXXkhuey this is probably wrong.
|
||||
return self.inner.tag()
|
||||
|
||||
def resolveType(self, parentScope):
|
||||
|
@ -858,10 +850,11 @@ class IDLSequenceType(IDLType):
|
|||
|
||||
def complete(self, scope):
|
||||
self.inner = self.inner.complete(scope)
|
||||
self.name = self.inner.name
|
||||
return self
|
||||
|
||||
def unroll(self):
|
||||
return self.inner
|
||||
return self.inner.unroll()
|
||||
|
||||
def isDistinguishableFrom(self, other):
|
||||
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
||||
|
@ -895,32 +888,33 @@ class IDLArrayType(IDLType):
|
|||
return False
|
||||
|
||||
def isPrimitive(self):
|
||||
return self.inner.isPrimitive()
|
||||
return False
|
||||
|
||||
def isString(self):
|
||||
return self.inner.isString()
|
||||
return False
|
||||
|
||||
def isVoid(self):
|
||||
return False
|
||||
|
||||
def isSequence(self):
|
||||
assert not self.inner.isSequence()
|
||||
return self.inner.isSequence()
|
||||
return False
|
||||
|
||||
def isArray(self):
|
||||
return True
|
||||
|
||||
def isDictionary(self):
|
||||
assert not self.inner.isDictionary()
|
||||
return self.inner.isDictionary()
|
||||
return False
|
||||
|
||||
def isInterface(self):
|
||||
return self.inner.isInterface()
|
||||
return False
|
||||
|
||||
def isEnum(self):
|
||||
return self.inner.isEnum()
|
||||
return False
|
||||
|
||||
def tag(self):
|
||||
# XXXkhuey this is probably wrong.
|
||||
return self.inner.tag()
|
||||
|
||||
def resolveType(self, parentScope):
|
||||
|
@ -932,10 +926,11 @@ class IDLArrayType(IDLType):
|
|||
|
||||
def complete(self, scope):
|
||||
self.inner = self.inner.complete(scope)
|
||||
self.name = self.inner.name
|
||||
return self
|
||||
|
||||
def unroll(self):
|
||||
return self.inner
|
||||
return self.inner.unroll()
|
||||
|
||||
def isDistinguishableFrom(self, other):
|
||||
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
||||
|
@ -995,7 +990,7 @@ class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
|
|||
return self.inner.tag()
|
||||
|
||||
def unroll(self):
|
||||
return self.inner
|
||||
return self.inner.unroll()
|
||||
|
||||
def isDistinguishableFrom(self, other):
|
||||
return self.inner.isDistinguishableFrom(other)
|
||||
|
@ -1041,6 +1036,10 @@ class IDLWrapperType(IDLType):
|
|||
def isEnum(self):
|
||||
return isinstance(self.inner, IDLEnum)
|
||||
|
||||
def resolveType(self, parentScope):
|
||||
assert isinstance(parentScope, IDLScope)
|
||||
self.inner.resolve(parentScope)
|
||||
|
||||
def isComplete(self):
|
||||
return True
|
||||
|
||||
|
@ -1122,32 +1121,32 @@ class IDLBuiltinType(IDLType):
|
|||
def __init__(self, location, name, type):
|
||||
IDLType.__init__(self, location, name)
|
||||
self.builtin = True
|
||||
self.type = type
|
||||
self._typeTag = type
|
||||
|
||||
def isPrimitive(self):
|
||||
return self.type <= IDLBuiltinType.Types.double
|
||||
return self._typeTag <= IDLBuiltinType.Types.double
|
||||
|
||||
def isString(self):
|
||||
return self.type == IDLBuiltinType.Types.domstring
|
||||
return self._typeTag == IDLBuiltinType.Types.domstring
|
||||
|
||||
def isInteger(self):
|
||||
return self.type <= IDLBuiltinType.Types.unsigned_long_long
|
||||
return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long
|
||||
|
||||
def isArrayBuffer(self):
|
||||
return self.type == IDLBuiltinType.Types.ArrayBuffer
|
||||
return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
|
||||
|
||||
def isInterface(self):
|
||||
# ArrayBuffers are interface types per the TypedArray spec,
|
||||
# but we handle them as builtins because SpiderMonkey implements
|
||||
# ArrayBuffers.
|
||||
return self.type == IDLBuiltinType.Types.ArrayBuffer
|
||||
return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
|
||||
|
||||
def isFloat(self):
|
||||
return self.type == IDLBuiltinType.Types.float or \
|
||||
self.type == IDLBuiltinType.Types.double
|
||||
return self._typeTag == IDLBuiltinType.Types.float or \
|
||||
self._typeTag == IDLBuiltinType.Types.double
|
||||
|
||||
def tag(self):
|
||||
return IDLBuiltinType.TagLookup[self.type]
|
||||
return IDLBuiltinType.TagLookup[self._typeTag]
|
||||
|
||||
def isDistinguishableFrom(self, other):
|
||||
if self.isPrimitive() or self.isString():
|
||||
|
@ -1280,7 +1279,7 @@ class IDLValue(IDLObject):
|
|||
|
||||
# We're both integer types. See if we fit.
|
||||
|
||||
(min, max) = integerTypeSizes[type.type]
|
||||
(min, max) = integerTypeSizes[type._typeTag]
|
||||
if self.value <= max and self.value >= min:
|
||||
# Promote
|
||||
return IDLValue(self.location, type, self.value)
|
||||
|
@ -1492,8 +1491,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
)
|
||||
|
||||
def __init__(self, location, identifier, returnType, arguments,
|
||||
static, getter, setter, creator, deleter, specialType, legacycaller,
|
||||
stringifier):
|
||||
static=False, getter=False, setter=False, creator=False,
|
||||
deleter=False, specialType=NamedOrIndexed.Neither,
|
||||
legacycaller=False, stringifier=False):
|
||||
# REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
|
||||
IDLInterfaceMember.__init__(self, location, identifier,
|
||||
IDLInterfaceMember.Tags.Method)
|
||||
|
||||
|
@ -1678,6 +1679,7 @@ class Tokenizer(object):
|
|||
def t_INTEGER(self, t):
|
||||
r'-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)'
|
||||
try:
|
||||
# Can't use int(), because that doesn't handle octal properly.
|
||||
t.value = parseInt(t.value)
|
||||
except:
|
||||
raise WebIDLError("Invalid integer literal",
|
||||
|
@ -2261,8 +2263,9 @@ class Parser(Tokenizer):
|
|||
"legacycaller" if legacycaller else ""), allowDoubleUnderscore=True)
|
||||
|
||||
method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments,
|
||||
static, getter, setter, creator, deleter, specialType,
|
||||
legacycaller, False)
|
||||
static=static, getter=getter, setter=setter, creator=creator,
|
||||
deleter=deleter, specialType=specialType,
|
||||
legacycaller=legacycaller, stringifier=False)
|
||||
p[0] = method
|
||||
|
||||
def p_QualifiersStatic(self, p):
|
||||
|
@ -2861,7 +2864,14 @@ class Parser(Tokenizer):
|
|||
for production in self._productions:
|
||||
production.finish(self.globalScope())
|
||||
|
||||
return set(self._productions)
|
||||
# De-duplicate self._productions, without modifying its order.
|
||||
seen = set()
|
||||
result = []
|
||||
for p in self._productions:
|
||||
if p not in seen:
|
||||
seen.add(p)
|
||||
result.append(p)
|
||||
return result
|
||||
|
||||
def reset(self):
|
||||
return Parser()
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
__all__ = ['WebIDL']
|
|
@ -37,36 +37,76 @@
|
|||
|
||||
import os, sys
|
||||
import glob
|
||||
import optparse
|
||||
import traceback
|
||||
import WebIDL
|
||||
|
||||
class TestHarness(object):
|
||||
def __init__(self, test, verbose):
|
||||
self.test = test
|
||||
self.verbose = verbose
|
||||
self.printed_intro = False
|
||||
|
||||
def start(self):
|
||||
if self.verbose:
|
||||
self.maybe_print_intro()
|
||||
|
||||
def finish(self):
|
||||
if self.verbose or self.printed_intro:
|
||||
print "Finished test %s" % self.test
|
||||
|
||||
def maybe_print_intro(self):
|
||||
if not self.printed_intro:
|
||||
print "Starting test %s" % self.test
|
||||
self.printed_intro = True
|
||||
|
||||
def test_pass(self, msg):
|
||||
if self.verbose:
|
||||
print "TEST-PASS | %s" % msg
|
||||
|
||||
def test_fail(self, msg):
|
||||
self.maybe_print_intro()
|
||||
print "TEST-UNEXPECTED-FAIL | %s" % msg
|
||||
|
||||
def ok(self, condition, msg):
|
||||
if condition:
|
||||
print "TEST-PASS | %s" % msg
|
||||
self.test_pass(msg)
|
||||
else:
|
||||
print "TEST-UNEXPECTED-FAIL | %s" % msg
|
||||
self.test_fail(msg)
|
||||
|
||||
def check(self, a, b, msg):
|
||||
if a == b:
|
||||
print "TEST-PASS | %s" % msg
|
||||
self.test_pass(msg)
|
||||
else:
|
||||
print "TEST-UNEXPECTED-FAIL | %s" % msg
|
||||
self.test_fail(msg)
|
||||
print "\tGot %s expected %s" % (a, b)
|
||||
|
||||
def run_tests():
|
||||
harness = TestHarness()
|
||||
def run_tests(tests, verbose):
|
||||
testdir = os.path.join(os.path.dirname(__file__), 'tests')
|
||||
if not tests:
|
||||
tests = glob.iglob(os.path.join(testdir, "*.py"))
|
||||
sys.path.append(testdir)
|
||||
|
||||
tests = glob.iglob("tests/*.py")
|
||||
sys.path.append("./tests")
|
||||
for test in tests:
|
||||
(testpath, ext) = os.path.splitext(os.path.basename(test))
|
||||
_test = __import__(testpath, globals(), locals(), ['WebIDLTest'])
|
||||
#try:
|
||||
_test.WebIDLTest.__call__(WebIDL.Parser(), harness)
|
||||
#except:
|
||||
# print "TEST-UNEXPECTED-FAIL | Unhandled exception in Test %s" % testpath
|
||||
# print sys.exc_info()[0]
|
||||
print "Test %s Complete\n" % testpath
|
||||
|
||||
harness = TestHarness(test, verbose)
|
||||
harness.start()
|
||||
try:
|
||||
_test.WebIDLTest.__call__(WebIDL.Parser(), harness)
|
||||
except:
|
||||
print "TEST-UNEXPECTED-FAIL | Unhandled exception in test %s" % testpath
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
harness.finish()
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_tests()
|
||||
usage = """%prog [OPTIONS] [TESTS]
|
||||
Where TESTS are relative to the tests directory."""
|
||||
parser = optparse.OptionParser(usage=usage)
|
||||
parser.add_option('-q', '--quiet', action='store_false', dest='verbose', default=True,
|
||||
help="Don't print passing tests.")
|
||||
options, tests = parser.parse_args()
|
||||
|
||||
run_tests(tests, verbose=options.verbose)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import WebIDL
|
||||
|
||||
def WebIDLTest(parser, harness):
|
||||
parser.parse("""
|
||||
interface A {
|
||||
attribute long a;
|
||||
};
|
||||
|
||||
interface B {
|
||||
attribute A[] b;
|
||||
};
|
||||
""");
|
||||
parser.finish()
|
|
@ -0,0 +1,11 @@
|
|||
import WebIDL
|
||||
|
||||
def WebIDLTest(parser, harness):
|
||||
parser.parse("""
|
||||
interface Test {
|
||||
attribute long b;
|
||||
};
|
||||
""");
|
||||
|
||||
attr = parser.finish()[0].members[0]
|
||||
harness.check(attr.type.filename(), '<builtin>', 'Filename on builtin type')
|
|
@ -62,14 +62,14 @@ def WebIDLTest(parser, harness):
|
|||
"Should be an IDLInterface")
|
||||
|
||||
checkMethod(results[0].ctor(), "::TestConstructorNoArgs::constructor",
|
||||
"constructor", [("TestConstructorNoArgs", [])])
|
||||
"constructor", [("TestConstructorNoArgs (Wrapper)", [])])
|
||||
checkMethod(results[1].ctor(), "::TestConstructorWithArgs::constructor",
|
||||
"constructor",
|
||||
[("TestConstructorWithArgs",
|
||||
[("TestConstructorWithArgs (Wrapper)",
|
||||
[("::TestConstructorWithArgs::constructor::name", "name", "String", False, False)])])
|
||||
checkMethod(results[2].ctor(), "::TestConstructorOverloads::constructor",
|
||||
"constructor",
|
||||
[("TestConstructorOverloads",
|
||||
[("TestConstructorOverloads (Wrapper)",
|
||||
[("::TestConstructorOverloads::constructor::foo", "foo", "Object", False, False)]),
|
||||
("TestConstructorOverloads",
|
||||
("TestConstructorOverloads (Wrapper)",
|
||||
[("::TestConstructorOverloads::constructor::bar", "bar", "Boolean", False, False)])])
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import WebIDL
|
||||
|
||||
def WebIDLTest(parser, harness):
|
||||
parser.parse("""
|
||||
interface Foo;
|
||||
interface Bar;
|
||||
interface Foo;
|
||||
""");
|
||||
|
||||
results = parser.finish()
|
||||
|
||||
# There should be no duplicate interfaces in the result.
|
||||
expectedNames = sorted(['Foo', 'Bar'])
|
||||
actualNames = sorted(map(lambda iface: iface.identifier.name, results))
|
||||
harness.check(actualNames, expectedNames, "Parser shouldn't output duplicate names.")
|
|
@ -47,7 +47,7 @@ def WebIDLTest(parser, harness):
|
|||
harness.check(len(signatures), 1, "Expect one signature")
|
||||
|
||||
(returnType, arguments) = signatures[0]
|
||||
harness.check(str(returnType), "TestEnum", "Method type is the correct name")
|
||||
harness.check(str(returnType), "TestEnum (Wrapper)", "Method type is the correct name")
|
||||
harness.check(len(arguments), 1, "Method has the right number of arguments")
|
||||
arg = arguments[0]
|
||||
harness.ok(isinstance(arg, WebIDL.IDLArgument), "Should be an IDLArgument")
|
||||
|
@ -58,4 +58,4 @@ def WebIDLTest(parser, harness):
|
|||
"Attr has correct QName")
|
||||
harness.check(attr.identifier.name, "foo", "Attr has correct name")
|
||||
|
||||
harness.check(str(attr.type), "TestEnum", "Attr type is the correct name")
|
||||
harness.check(str(attr.type), "TestEnum (Wrapper)", "Attr type is the correct name")
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import WebIDL
|
||||
|
||||
def WebIDLTest(parser, harness):
|
||||
# Check that error messages put the '^' in the right place.
|
||||
|
||||
threw = False
|
||||
input = 'interface ?'
|
||||
try:
|
||||
parser.parse(input)
|
||||
results = parser.finish()
|
||||
except WebIDL.WebIDLError as e:
|
||||
threw = True
|
||||
lines = str(e).split('\n')
|
||||
|
||||
harness.check(len(lines), 3, 'Expected number of lines in error message')
|
||||
harness.check(lines[1], input, 'Second line shows error')
|
||||
harness.check(lines[2], ' ' * (len(input) - 1) + '^',
|
||||
'Correct column pointer in error message')
|
||||
|
||||
harness.ok(threw, "Should have thrown.")
|
|
@ -0,0 +1,134 @@
|
|||
import WebIDL
|
||||
|
||||
def WebIDLTest(parser, harness):
|
||||
parser.parse("""
|
||||
interface TestNullableEquivalency1 {
|
||||
attribute long a;
|
||||
attribute long? b;
|
||||
};
|
||||
|
||||
interface TestNullableEquivalency2 {
|
||||
attribute ArrayBuffer a;
|
||||
attribute ArrayBuffer? b;
|
||||
};
|
||||
|
||||
/* Not implemented */
|
||||
/*dictionary TestNullableEquivalency3Dict {
|
||||
long foo = 42;
|
||||
};
|
||||
|
||||
interface TestNullableEquivalency3 {
|
||||
attribute Test3Dict a;
|
||||
attribute Test3Dict? b;
|
||||
};*/
|
||||
|
||||
enum TestNullableEquivalency4Enum {
|
||||
"Foo",
|
||||
"Bar"
|
||||
};
|
||||
|
||||
interface TestNullableEquivalency4 {
|
||||
attribute TestNullableEquivalency4Enum a;
|
||||
attribute TestNullableEquivalency4Enum? b;
|
||||
};
|
||||
|
||||
interface TestNullableEquivalency5 {
|
||||
attribute TestNullableEquivalency4 a;
|
||||
attribute TestNullableEquivalency4? b;
|
||||
};
|
||||
|
||||
interface TestNullableEquivalency6 {
|
||||
attribute boolean a;
|
||||
attribute boolean? b;
|
||||
};
|
||||
|
||||
interface TestNullableEquivalency7 {
|
||||
attribute DOMString a;
|
||||
attribute DOMString? b;
|
||||
};
|
||||
|
||||
/* Not implemented. */
|
||||
/*interface TestNullableEquivalency8 {
|
||||
attribute float a;
|
||||
attribute float? b;
|
||||
};*/
|
||||
|
||||
interface TestNullableEquivalency8 {
|
||||
attribute double a;
|
||||
attribute double? b;
|
||||
};
|
||||
|
||||
interface TestNullableEquivalency9 {
|
||||
attribute object a;
|
||||
attribute object? b;
|
||||
};
|
||||
|
||||
interface TestNullableEquivalency10 {
|
||||
attribute double[] a;
|
||||
attribute double[]? b;
|
||||
};
|
||||
|
||||
interface TestNullableEquivalency11 {
|
||||
attribute TestNullableEquivalency9[] a;
|
||||
attribute TestNullableEquivalency9[]? b;
|
||||
};
|
||||
""")
|
||||
|
||||
for decl in parser.finish():
|
||||
if decl.isInterface():
|
||||
checkEquivalent(decl, harness)
|
||||
|
||||
def checkEquivalent(iface, harness):
|
||||
type1 = iface.members[0].type
|
||||
type2 = iface.members[1].type
|
||||
|
||||
harness.check(type1.nullable(), False, 'attr1 should not be nullable')
|
||||
harness.check(type2.nullable(), True, 'attr2 should be nullable')
|
||||
|
||||
# We don't know about type1, but type2, the nullable type, definitely
|
||||
# shouldn't be builtin.
|
||||
harness.check(type2.builtin, False, 'attr2 should not be builtin')
|
||||
|
||||
# Ensure that all attributes of type2 match those in type1, except for:
|
||||
# - names on an ignore list,
|
||||
# - names beginning with '_',
|
||||
# - functions which throw when called with no args, and
|
||||
# - class-level non-callables ("static variables").
|
||||
#
|
||||
# Yes, this is an ugly, fragile hack. But it finds bugs...
|
||||
for attr in dir(type1):
|
||||
if attr.startswith('_') or \
|
||||
attr in ['nullable', 'builtin', 'filename', 'location',
|
||||
'inner', 'QName'] or \
|
||||
(hasattr(type(type1), attr) and not callable(getattr(type1, attr))):
|
||||
continue
|
||||
|
||||
a1 = getattr(type1, attr)
|
||||
|
||||
if callable(a1):
|
||||
try:
|
||||
v1 = a1()
|
||||
except:
|
||||
# Can't call a1 with no args, so skip this attriute.
|
||||
continue
|
||||
|
||||
try:
|
||||
a2 = getattr(type2, attr)
|
||||
except:
|
||||
harness.ok(False, 'Missing %s attribute on type %s in %s' % (attr, type2, iface))
|
||||
continue
|
||||
|
||||
if not callable(a2):
|
||||
harness.ok(False, "%s attribute on type %s in %s wasn't callable" % (attr, type2, iface))
|
||||
continue
|
||||
|
||||
v2 = a2()
|
||||
harness.check(v2, v1, '%s method return value' % attr)
|
||||
else:
|
||||
try:
|
||||
a2 = getattr(type2, attr)
|
||||
except:
|
||||
harness.ok(False, 'Missing %s attribute on type %s in %s' % (attr, type2, iface))
|
||||
continue
|
||||
|
||||
harness.check(a2, a1, '%s attribute should match' % attr)
|
Загрузка…
Ссылка в новой задаче