зеркало из 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'))
|
('security/dbm', 'mozilla/security/dbm'))
|
||||||
NSSCKBI_DIRS = (('security/nss/lib/ckfw/builtins', 'mozilla/security/nss/lib/ckfw/builtins'),)
|
NSSCKBI_DIRS = (('security/nss/lib/ckfw/builtins', 'mozilla/security/nss/lib/ckfw/builtins'),)
|
||||||
LIBFFI_DIRS = (('js/ctypes/libffi', 'libffi'),)
|
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_MOZILLA = ':pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot'
|
||||||
CVSROOT_LIBFFI = ':pserver:anoncvs@sources.redhat.com:/cvs/libffi'
|
CVSROOT_LIBFFI = ':pserver:anoncvs@sources.redhat.com:/cvs/libffi'
|
||||||
|
@ -15,6 +18,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import datetime
|
import datetime
|
||||||
import shutil
|
import shutil
|
||||||
|
import glob
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
from subprocess import check_call
|
from subprocess import check_call
|
||||||
|
|
||||||
|
@ -30,7 +34,6 @@ def do_hg_pull(dir, repository, hg):
|
||||||
fulldir = os.path.join(topsrcdir, dir)
|
fulldir = os.path.join(topsrcdir, dir)
|
||||||
# clone if the dir doesn't exist, pull if it does
|
# clone if the dir doesn't exist, pull if it does
|
||||||
if not os.path.exists(fulldir):
|
if not os.path.exists(fulldir):
|
||||||
fulldir = os.path.join(topsrcdir, dir)
|
|
||||||
check_call_noisy([hg, 'clone', repository, fulldir])
|
check_call_noisy([hg, 'clone', repository, fulldir])
|
||||||
else:
|
else:
|
||||||
cmd = [hg, 'pull', '-u', '-R', fulldir]
|
cmd = [hg, 'pull', '-u', '-R', fulldir]
|
||||||
|
@ -40,6 +43,25 @@ def do_hg_pull(dir, repository, hg):
|
||||||
check_call([hg, 'parent', '-R', fulldir,
|
check_call([hg, 'parent', '-R', fulldir,
|
||||||
'--template=Updated to revision {node}.\n'])
|
'--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):
|
def do_cvs_export(modules, tag, cvsroot, cvs):
|
||||||
"""Check out a CVS directory without CVS metadata, using "export"
|
"""Check out a CVS directory without CVS metadata, using "export"
|
||||||
modules is a list of directories to check out and the corresponding
|
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))
|
cwd=os.path.join(topsrcdir, parent))
|
||||||
print "CVS export end: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
|
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",
|
o.add_option("--skip-mozilla", dest="skip_mozilla",
|
||||||
action="store_true", default=False,
|
action="store_true", default=False,
|
||||||
help="Obsolete")
|
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")
|
help="The location of the cvs binary")
|
||||||
o.add_option("--cvsroot", dest="cvsroot",
|
o.add_option("--cvsroot", dest="cvsroot",
|
||||||
help="The CVSROOT (default for mozilla checkouts: %s)" % CVSROOT_MOZILLA)
|
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:
|
try:
|
||||||
options, args = o.parse_args()
|
options, args = o.parse_args()
|
||||||
|
@ -104,6 +128,9 @@ elif action in ('update_libffi'):
|
||||||
if not options.cvsroot:
|
if not options.cvsroot:
|
||||||
options.cvsroot = CVSROOT_LIBFFI
|
options.cvsroot = CVSROOT_LIBFFI
|
||||||
do_cvs_export(LIBFFI_DIRS, tag, options.cvsroot, options.cvs)
|
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:
|
else:
|
||||||
o.print_help()
|
o.print_help()
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
|
@ -75,7 +75,7 @@ bindinggen_dependencies := \
|
||||||
$(binding_header_files): %Binding.h: $(bindinggen_dependencies) \
|
$(binding_header_files): %Binding.h: $(bindinggen_dependencies) \
|
||||||
$(webidl_base)/%.webidl \
|
$(webidl_base)/%.webidl \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||||
$(PLY_INCLUDE) -I$(srcdir)/parser \
|
$(PLY_INCLUDE) -I$(srcdir)/parser \
|
||||||
$(srcdir)/BindingGen.py $(ACCESSOR_OPT) header \
|
$(srcdir)/BindingGen.py $(ACCESSOR_OPT) header \
|
||||||
$(srcdir)/Bindings.conf $*Binding \
|
$(srcdir)/Bindings.conf $*Binding \
|
||||||
|
@ -84,7 +84,7 @@ $(binding_header_files): %Binding.h: $(bindinggen_dependencies) \
|
||||||
$(binding_cpp_files): %Binding.cpp: $(bindinggen_dependencies) \
|
$(binding_cpp_files): %Binding.cpp: $(bindinggen_dependencies) \
|
||||||
$(webidl_base)/%.webidl \
|
$(webidl_base)/%.webidl \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||||
$(PLY_INCLUDE) -I$(srcdir)/parser \
|
$(PLY_INCLUDE) -I$(srcdir)/parser \
|
||||||
$(srcdir)/BindingGen.py $(ACCESSOR_OPT) cpp \
|
$(srcdir)/BindingGen.py $(ACCESSOR_OPT) cpp \
|
||||||
$(srcdir)/Bindings.conf $*Binding \
|
$(srcdir)/Bindings.conf $*Binding \
|
||||||
|
@ -109,7 +109,7 @@ $(CACHE_DIR)/.done:
|
||||||
|
|
||||||
ParserResults.pkl: $(globalgen_dependencies) \
|
ParserResults.pkl: $(globalgen_dependencies) \
|
||||||
$(addprefix $(webidl_base)/, $(webidl_files))
|
$(addprefix $(webidl_base)/, $(webidl_files))
|
||||||
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||||
$(PLY_INCLUDE) -I$(srcdir)/parser \
|
$(PLY_INCLUDE) -I$(srcdir)/parser \
|
||||||
$(srcdir)/GlobalGen.py $(ACCESSOR_OPT) $(srcdir)/Bindings.conf $(webidl_base) \
|
$(srcdir)/GlobalGen.py $(ACCESSOR_OPT) $(srcdir)/Bindings.conf $(webidl_base) \
|
||||||
--cachedir=$(CACHE_DIR) \
|
--cachedir=$(CACHE_DIR) \
|
||||||
|
|
|
@ -69,14 +69,16 @@ def parseInt(literal):
|
||||||
# Magic for creating enums
|
# Magic for creating enums
|
||||||
def M_add_class_attribs(attribs):
|
def M_add_class_attribs(attribs):
|
||||||
def foo(name, bases, dict_):
|
def foo(name, bases, dict_):
|
||||||
for v, k in attribs:
|
for v, k in enumerate(attribs):
|
||||||
dict_[k] = v
|
dict_[k] = v
|
||||||
|
assert 'length' not in dict_
|
||||||
|
dict_['length'] = len(attribs)
|
||||||
return type(name, bases, dict_)
|
return type(name, bases, dict_)
|
||||||
return foo
|
return foo
|
||||||
|
|
||||||
def enum(*names):
|
def enum(*names):
|
||||||
class Foo(object):
|
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
|
def __setattr__(self, name, value): # this makes it read-only
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
return Foo()
|
return Foo()
|
||||||
|
@ -93,9 +95,8 @@ class WebIDLError(Exception):
|
||||||
self.location)
|
self.location)
|
||||||
|
|
||||||
class Location(object):
|
class Location(object):
|
||||||
_line = None
|
|
||||||
|
|
||||||
def __init__(self, lexer, lineno, lexpos, filename):
|
def __init__(self, lexer, lineno, lexpos, filename):
|
||||||
|
self._line = None
|
||||||
self._lineno = lineno
|
self._lineno = lineno
|
||||||
self._lexpos = lexpos
|
self._lexpos = lexpos
|
||||||
self._lexdata = lexer.lexdata
|
self._lexdata = lexer.lexdata
|
||||||
|
@ -105,36 +106,47 @@ class Location(object):
|
||||||
return self._lexpos == other._lexpos and \
|
return self._lexpos == other._lexpos and \
|
||||||
self._file == other._file
|
self._file == other._file
|
||||||
|
|
||||||
|
def filename(self):
|
||||||
|
return self._file
|
||||||
|
|
||||||
def resolve(self):
|
def resolve(self):
|
||||||
if self._line:
|
if self._line:
|
||||||
return
|
return
|
||||||
|
|
||||||
startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1
|
startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1
|
||||||
endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80)
|
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
|
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):
|
def get(self):
|
||||||
self.resolve()
|
self.resolve()
|
||||||
return "%s line %s:%s" % (self._file, self._lineno, self._colno)
|
return "%s line %s:%s" % (self._file, self._lineno, self._colno)
|
||||||
|
|
||||||
|
def _pointerline(self):
|
||||||
|
return " " * self._colno + "^"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
self.resolve()
|
self.resolve()
|
||||||
return "%s line %s:%s\n%s\n%s" % (self._file, self._lineno, self._colno,
|
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):
|
class BuiltinLocation(object):
|
||||||
def __init__(self, text):
|
def __init__(self, text):
|
||||||
self.msg = 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):
|
def get(self):
|
||||||
return self.msg
|
return self.msg
|
||||||
|
|
||||||
|
@ -150,7 +162,7 @@ class IDLObject(object):
|
||||||
self.userData = dict()
|
self.userData = dict()
|
||||||
|
|
||||||
def filename(self):
|
def filename(self):
|
||||||
return self.location._file
|
return self.location.filename()
|
||||||
|
|
||||||
def isInterface(self):
|
def isInterface(self):
|
||||||
return False
|
return False
|
||||||
|
@ -198,6 +210,11 @@ class IDLScope(IDLObject):
|
||||||
return "::"
|
return "::"
|
||||||
|
|
||||||
def ensureUnique(self, identifier, object):
|
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 isinstance(identifier, IDLUnresolvedIdentifier)
|
||||||
assert not object or isinstance(object, IDLObjectWithIdentifier)
|
assert not object or isinstance(object, IDLObjectWithIdentifier)
|
||||||
assert not object or object.identifier == identifier
|
assert not object or object.identifier == identifier
|
||||||
|
@ -300,6 +317,9 @@ class IDLUnresolvedIdentifier(IDLObject):
|
||||||
object.identifier = identifier
|
object.identifier = identifier
|
||||||
return identifier
|
return identifier
|
||||||
|
|
||||||
|
def finish(self):
|
||||||
|
assert False # Should replace with a resolved identifier first.
|
||||||
|
|
||||||
class IDLObjectWithIdentifier(IDLObject):
|
class IDLObjectWithIdentifier(IDLObject):
|
||||||
def __init__(self, location, parentScope, identifier):
|
def __init__(self, location, parentScope, identifier):
|
||||||
IDLObject.__init__(self, location)
|
IDLObject.__init__(self, location)
|
||||||
|
@ -368,9 +388,8 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
|
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self._callback = False
|
self._callback = False
|
||||||
|
self._finished = False
|
||||||
self.members = list(members) # clone the list
|
self.members = list(members) # clone the list
|
||||||
assert iter(self.members) # Assert it's iterable
|
|
||||||
|
|
||||||
IDLObjectWithScope.__init__(self, location, parentScope, name)
|
IDLObjectWithScope.__init__(self, location, parentScope, name)
|
||||||
|
|
||||||
|
@ -404,7 +423,7 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
def finish(self, scope):
|
def finish(self, scope):
|
||||||
if hasattr(self, "_finished"):
|
if self._finished:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._finished = True
|
self._finished = True
|
||||||
|
@ -416,7 +435,6 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
assert iter(self.members)
|
assert iter(self.members)
|
||||||
members = None
|
|
||||||
|
|
||||||
if self.parent:
|
if self.parent:
|
||||||
self.parent.finish(scope)
|
self.parent.finish(scope)
|
||||||
|
@ -427,19 +445,6 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
else:
|
else:
|
||||||
members = list(self.members)
|
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):
|
def memberNotOnParentChain(member, iface):
|
||||||
assert iface
|
assert iface
|
||||||
|
|
||||||
|
@ -451,59 +456,39 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
return False
|
return False
|
||||||
return memberNotOnParentChain(member, iface.parent)
|
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:
|
for member in members:
|
||||||
if memberNotOnParentChain(member, self):
|
if memberNotOnParentChain(member, self):
|
||||||
member.resolve(self)
|
member.resolve(self)
|
||||||
|
|
||||||
if member.tag == IDLInterfaceMember.Tags.Method:
|
if member.tag != IDLInterfaceMember.Tags.Method:
|
||||||
if member.isGetter():
|
continue
|
||||||
if member.isNamed():
|
|
||||||
if specialMembersSeen[SpecialType.NamedGetter]:
|
if member.isGetter():
|
||||||
raise WebIDLError("Multiple named getters on %s" % (self),
|
memberType = "getters"
|
||||||
self.location)
|
elif member.isSetter():
|
||||||
specialMembersSeen[SpecialType.NamedGetter] = True
|
memberType = "setters"
|
||||||
else:
|
elif member.isCreator():
|
||||||
assert member.isIndexed()
|
memberType = "creators"
|
||||||
if specialMembersSeen[SpecialType.IndexedGetter]:
|
elif member.isDeleter():
|
||||||
raise WebIDLError("Multiple indexed getters on %s" % (self),
|
memberType = "deleters"
|
||||||
self.location)
|
else:
|
||||||
specialMembersSeen[SpecialType.IndexedGetter] = True
|
continue
|
||||||
if member.isSetter():
|
|
||||||
if member.isNamed():
|
if member.isNamed():
|
||||||
if specialMembersSeen[SpecialType.NamedSetter]:
|
memberType = "named " + memberType
|
||||||
raise WebIDLError("Multiple named setters on %s" % (self),
|
elif member.isIndexed():
|
||||||
self.location)
|
memberType = "indexed " + memberType
|
||||||
specialMembersSeen[SpecialType.NamedSetter] = True
|
else:
|
||||||
else:
|
continue
|
||||||
assert member.isIndexed()
|
|
||||||
if specialMembersSeen[SpecialType.IndexedSetter]:
|
if memberType in specialMembersSeen:
|
||||||
raise WebIDLError("Multiple indexed setters on %s" % (self),
|
raise WebIDLError("Multiple " + memberType + " on %s" % (self),
|
||||||
self.location)
|
self.location)
|
||||||
specialMembersSeen[SpecialType.IndexedSetter] = True
|
|
||||||
if member.isCreator():
|
specialMembersSeen.add(memberType)
|
||||||
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
|
|
||||||
|
|
||||||
for member in self.members:
|
for member in self.members:
|
||||||
member.finish(scope)
|
member.finish(scope)
|
||||||
|
@ -529,7 +514,7 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
return depth
|
return depth
|
||||||
|
|
||||||
def hasConstants(self):
|
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):
|
def hasInterfaceObject(self):
|
||||||
if self.isCallback():
|
if self.isCallback():
|
||||||
|
@ -567,10 +552,7 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
identifier = IDLUnresolvedIdentifier(self.location, "constructor",
|
identifier = IDLUnresolvedIdentifier(self.location, "constructor",
|
||||||
allowForbidden=True)
|
allowForbidden=True)
|
||||||
|
|
||||||
method = IDLMethod(self.location, identifier, retType, args,
|
method = IDLMethod(self.location, identifier, retType, args)
|
||||||
False, False, False, False, False, False,
|
|
||||||
False, False)
|
|
||||||
|
|
||||||
method.resolve(self)
|
method.resolve(self)
|
||||||
|
|
||||||
self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
|
self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
|
||||||
|
@ -763,6 +745,12 @@ class IDLNullableType(IDLType):
|
||||||
def isString(self):
|
def isString(self):
|
||||||
return self.inner.isString()
|
return self.inner.isString()
|
||||||
|
|
||||||
|
def isFloat(self):
|
||||||
|
return self.inner.isFloat()
|
||||||
|
|
||||||
|
def isInteger(self):
|
||||||
|
return self.inner.isInteger()
|
||||||
|
|
||||||
def isVoid(self):
|
def isVoid(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -772,6 +760,9 @@ class IDLNullableType(IDLType):
|
||||||
def isArray(self):
|
def isArray(self):
|
||||||
return self.inner.isArray()
|
return self.inner.isArray()
|
||||||
|
|
||||||
|
def isArrayBuffer(self):
|
||||||
|
return self.inner.isArrayBuffer()
|
||||||
|
|
||||||
def isDictionary(self):
|
def isDictionary(self):
|
||||||
return self.inner.isDictionary()
|
return self.inner.isDictionary()
|
||||||
|
|
||||||
|
@ -797,7 +788,7 @@ class IDLNullableType(IDLType):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def unroll(self):
|
def unroll(self):
|
||||||
return self.inner
|
return self.inner.unroll()
|
||||||
|
|
||||||
def isDistinguishableFrom(self, other):
|
def isDistinguishableFrom(self, other):
|
||||||
if other.nullable():
|
if other.nullable():
|
||||||
|
@ -835,18 +826,19 @@ class IDLSequenceType(IDLType):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def isArray(self):
|
def isArray(self):
|
||||||
return self.inner.isArray()
|
return False
|
||||||
|
|
||||||
def isDictionary(self):
|
def isDictionary(self):
|
||||||
return self.inner.isDictionary()
|
return False
|
||||||
|
|
||||||
def isInterface(self):
|
def isInterface(self):
|
||||||
return self.inner.isInterface()
|
return False
|
||||||
|
|
||||||
def isEnum(self):
|
def isEnum(self):
|
||||||
return self.inner.isEnum();
|
return False
|
||||||
|
|
||||||
def tag(self):
|
def tag(self):
|
||||||
|
# XXXkhuey this is probably wrong.
|
||||||
return self.inner.tag()
|
return self.inner.tag()
|
||||||
|
|
||||||
def resolveType(self, parentScope):
|
def resolveType(self, parentScope):
|
||||||
|
@ -858,10 +850,11 @@ class IDLSequenceType(IDLType):
|
||||||
|
|
||||||
def complete(self, scope):
|
def complete(self, scope):
|
||||||
self.inner = self.inner.complete(scope)
|
self.inner = self.inner.complete(scope)
|
||||||
|
self.name = self.inner.name
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def unroll(self):
|
def unroll(self):
|
||||||
return self.inner
|
return self.inner.unroll()
|
||||||
|
|
||||||
def isDistinguishableFrom(self, other):
|
def isDistinguishableFrom(self, other):
|
||||||
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
||||||
|
@ -895,32 +888,33 @@ class IDLArrayType(IDLType):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def isPrimitive(self):
|
def isPrimitive(self):
|
||||||
return self.inner.isPrimitive()
|
return False
|
||||||
|
|
||||||
def isString(self):
|
def isString(self):
|
||||||
return self.inner.isString()
|
return False
|
||||||
|
|
||||||
def isVoid(self):
|
def isVoid(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def isSequence(self):
|
def isSequence(self):
|
||||||
assert not self.inner.isSequence()
|
assert not self.inner.isSequence()
|
||||||
return self.inner.isSequence()
|
return False
|
||||||
|
|
||||||
def isArray(self):
|
def isArray(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def isDictionary(self):
|
def isDictionary(self):
|
||||||
assert not self.inner.isDictionary()
|
assert not self.inner.isDictionary()
|
||||||
return self.inner.isDictionary()
|
return False
|
||||||
|
|
||||||
def isInterface(self):
|
def isInterface(self):
|
||||||
return self.inner.isInterface()
|
return False
|
||||||
|
|
||||||
def isEnum(self):
|
def isEnum(self):
|
||||||
return self.inner.isEnum()
|
return False
|
||||||
|
|
||||||
def tag(self):
|
def tag(self):
|
||||||
|
# XXXkhuey this is probably wrong.
|
||||||
return self.inner.tag()
|
return self.inner.tag()
|
||||||
|
|
||||||
def resolveType(self, parentScope):
|
def resolveType(self, parentScope):
|
||||||
|
@ -932,10 +926,11 @@ class IDLArrayType(IDLType):
|
||||||
|
|
||||||
def complete(self, scope):
|
def complete(self, scope):
|
||||||
self.inner = self.inner.complete(scope)
|
self.inner = self.inner.complete(scope)
|
||||||
|
self.name = self.inner.name
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def unroll(self):
|
def unroll(self):
|
||||||
return self.inner
|
return self.inner.unroll()
|
||||||
|
|
||||||
def isDistinguishableFrom(self, other):
|
def isDistinguishableFrom(self, other):
|
||||||
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
||||||
|
@ -995,7 +990,7 @@ class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
|
||||||
return self.inner.tag()
|
return self.inner.tag()
|
||||||
|
|
||||||
def unroll(self):
|
def unroll(self):
|
||||||
return self.inner
|
return self.inner.unroll()
|
||||||
|
|
||||||
def isDistinguishableFrom(self, other):
|
def isDistinguishableFrom(self, other):
|
||||||
return self.inner.isDistinguishableFrom(other)
|
return self.inner.isDistinguishableFrom(other)
|
||||||
|
@ -1041,6 +1036,10 @@ class IDLWrapperType(IDLType):
|
||||||
def isEnum(self):
|
def isEnum(self):
|
||||||
return isinstance(self.inner, IDLEnum)
|
return isinstance(self.inner, IDLEnum)
|
||||||
|
|
||||||
|
def resolveType(self, parentScope):
|
||||||
|
assert isinstance(parentScope, IDLScope)
|
||||||
|
self.inner.resolve(parentScope)
|
||||||
|
|
||||||
def isComplete(self):
|
def isComplete(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -1122,32 +1121,32 @@ class IDLBuiltinType(IDLType):
|
||||||
def __init__(self, location, name, type):
|
def __init__(self, location, name, type):
|
||||||
IDLType.__init__(self, location, name)
|
IDLType.__init__(self, location, name)
|
||||||
self.builtin = True
|
self.builtin = True
|
||||||
self.type = type
|
self._typeTag = type
|
||||||
|
|
||||||
def isPrimitive(self):
|
def isPrimitive(self):
|
||||||
return self.type <= IDLBuiltinType.Types.double
|
return self._typeTag <= IDLBuiltinType.Types.double
|
||||||
|
|
||||||
def isString(self):
|
def isString(self):
|
||||||
return self.type == IDLBuiltinType.Types.domstring
|
return self._typeTag == IDLBuiltinType.Types.domstring
|
||||||
|
|
||||||
def isInteger(self):
|
def isInteger(self):
|
||||||
return self.type <= IDLBuiltinType.Types.unsigned_long_long
|
return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long
|
||||||
|
|
||||||
def isArrayBuffer(self):
|
def isArrayBuffer(self):
|
||||||
return self.type == IDLBuiltinType.Types.ArrayBuffer
|
return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
|
||||||
|
|
||||||
def isInterface(self):
|
def isInterface(self):
|
||||||
# ArrayBuffers are interface types per the TypedArray spec,
|
# ArrayBuffers are interface types per the TypedArray spec,
|
||||||
# but we handle them as builtins because SpiderMonkey implements
|
# but we handle them as builtins because SpiderMonkey implements
|
||||||
# ArrayBuffers.
|
# ArrayBuffers.
|
||||||
return self.type == IDLBuiltinType.Types.ArrayBuffer
|
return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
|
||||||
|
|
||||||
def isFloat(self):
|
def isFloat(self):
|
||||||
return self.type == IDLBuiltinType.Types.float or \
|
return self._typeTag == IDLBuiltinType.Types.float or \
|
||||||
self.type == IDLBuiltinType.Types.double
|
self._typeTag == IDLBuiltinType.Types.double
|
||||||
|
|
||||||
def tag(self):
|
def tag(self):
|
||||||
return IDLBuiltinType.TagLookup[self.type]
|
return IDLBuiltinType.TagLookup[self._typeTag]
|
||||||
|
|
||||||
def isDistinguishableFrom(self, other):
|
def isDistinguishableFrom(self, other):
|
||||||
if self.isPrimitive() or self.isString():
|
if self.isPrimitive() or self.isString():
|
||||||
|
@ -1280,7 +1279,7 @@ class IDLValue(IDLObject):
|
||||||
|
|
||||||
# We're both integer types. See if we fit.
|
# 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:
|
if self.value <= max and self.value >= min:
|
||||||
# Promote
|
# Promote
|
||||||
return IDLValue(self.location, type, self.value)
|
return IDLValue(self.location, type, self.value)
|
||||||
|
@ -1492,8 +1491,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, location, identifier, returnType, arguments,
|
def __init__(self, location, identifier, returnType, arguments,
|
||||||
static, getter, setter, creator, deleter, specialType, legacycaller,
|
static=False, getter=False, setter=False, creator=False,
|
||||||
stringifier):
|
deleter=False, specialType=NamedOrIndexed.Neither,
|
||||||
|
legacycaller=False, stringifier=False):
|
||||||
|
# REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
|
||||||
IDLInterfaceMember.__init__(self, location, identifier,
|
IDLInterfaceMember.__init__(self, location, identifier,
|
||||||
IDLInterfaceMember.Tags.Method)
|
IDLInterfaceMember.Tags.Method)
|
||||||
|
|
||||||
|
@ -1678,6 +1679,7 @@ class Tokenizer(object):
|
||||||
def t_INTEGER(self, t):
|
def t_INTEGER(self, t):
|
||||||
r'-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)'
|
r'-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)'
|
||||||
try:
|
try:
|
||||||
|
# Can't use int(), because that doesn't handle octal properly.
|
||||||
t.value = parseInt(t.value)
|
t.value = parseInt(t.value)
|
||||||
except:
|
except:
|
||||||
raise WebIDLError("Invalid integer literal",
|
raise WebIDLError("Invalid integer literal",
|
||||||
|
@ -2261,8 +2263,9 @@ class Parser(Tokenizer):
|
||||||
"legacycaller" if legacycaller else ""), allowDoubleUnderscore=True)
|
"legacycaller" if legacycaller else ""), allowDoubleUnderscore=True)
|
||||||
|
|
||||||
method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments,
|
method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments,
|
||||||
static, getter, setter, creator, deleter, specialType,
|
static=static, getter=getter, setter=setter, creator=creator,
|
||||||
legacycaller, False)
|
deleter=deleter, specialType=specialType,
|
||||||
|
legacycaller=legacycaller, stringifier=False)
|
||||||
p[0] = method
|
p[0] = method
|
||||||
|
|
||||||
def p_QualifiersStatic(self, p):
|
def p_QualifiersStatic(self, p):
|
||||||
|
@ -2861,7 +2864,14 @@ class Parser(Tokenizer):
|
||||||
for production in self._productions:
|
for production in self._productions:
|
||||||
production.finish(self.globalScope())
|
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):
|
def reset(self):
|
||||||
return Parser()
|
return Parser()
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
__all__ = ['WebIDL']
|
|
|
@ -37,36 +37,76 @@
|
||||||
|
|
||||||
import os, sys
|
import os, sys
|
||||||
import glob
|
import glob
|
||||||
|
import optparse
|
||||||
|
import traceback
|
||||||
import WebIDL
|
import WebIDL
|
||||||
|
|
||||||
class TestHarness(object):
|
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):
|
def ok(self, condition, msg):
|
||||||
if condition:
|
if condition:
|
||||||
print "TEST-PASS | %s" % msg
|
self.test_pass(msg)
|
||||||
else:
|
else:
|
||||||
print "TEST-UNEXPECTED-FAIL | %s" % msg
|
self.test_fail(msg)
|
||||||
|
|
||||||
def check(self, a, b, msg):
|
def check(self, a, b, msg):
|
||||||
if a == b:
|
if a == b:
|
||||||
print "TEST-PASS | %s" % msg
|
self.test_pass(msg)
|
||||||
else:
|
else:
|
||||||
print "TEST-UNEXPECTED-FAIL | %s" % msg
|
self.test_fail(msg)
|
||||||
print "\tGot %s expected %s" % (a, b)
|
print "\tGot %s expected %s" % (a, b)
|
||||||
|
|
||||||
def run_tests():
|
def run_tests(tests, verbose):
|
||||||
harness = TestHarness()
|
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:
|
for test in tests:
|
||||||
(testpath, ext) = os.path.splitext(os.path.basename(test))
|
(testpath, ext) = os.path.splitext(os.path.basename(test))
|
||||||
_test = __import__(testpath, globals(), locals(), ['WebIDLTest'])
|
_test = __import__(testpath, globals(), locals(), ['WebIDLTest'])
|
||||||
#try:
|
|
||||||
_test.WebIDLTest.__call__(WebIDL.Parser(), harness)
|
harness = TestHarness(test, verbose)
|
||||||
#except:
|
harness.start()
|
||||||
# print "TEST-UNEXPECTED-FAIL | Unhandled exception in Test %s" % testpath
|
try:
|
||||||
# print sys.exc_info()[0]
|
_test.WebIDLTest.__call__(WebIDL.Parser(), harness)
|
||||||
print "Test %s Complete\n" % testpath
|
except:
|
||||||
|
print "TEST-UNEXPECTED-FAIL | Unhandled exception in test %s" % testpath
|
||||||
|
traceback.print_exc()
|
||||||
|
finally:
|
||||||
|
harness.finish()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
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")
|
"Should be an IDLInterface")
|
||||||
|
|
||||||
checkMethod(results[0].ctor(), "::TestConstructorNoArgs::constructor",
|
checkMethod(results[0].ctor(), "::TestConstructorNoArgs::constructor",
|
||||||
"constructor", [("TestConstructorNoArgs", [])])
|
"constructor", [("TestConstructorNoArgs (Wrapper)", [])])
|
||||||
checkMethod(results[1].ctor(), "::TestConstructorWithArgs::constructor",
|
checkMethod(results[1].ctor(), "::TestConstructorWithArgs::constructor",
|
||||||
"constructor",
|
"constructor",
|
||||||
[("TestConstructorWithArgs",
|
[("TestConstructorWithArgs (Wrapper)",
|
||||||
[("::TestConstructorWithArgs::constructor::name", "name", "String", False, False)])])
|
[("::TestConstructorWithArgs::constructor::name", "name", "String", False, False)])])
|
||||||
checkMethod(results[2].ctor(), "::TestConstructorOverloads::constructor",
|
checkMethod(results[2].ctor(), "::TestConstructorOverloads::constructor",
|
||||||
"constructor",
|
"constructor",
|
||||||
[("TestConstructorOverloads",
|
[("TestConstructorOverloads (Wrapper)",
|
||||||
[("::TestConstructorOverloads::constructor::foo", "foo", "Object", False, False)]),
|
[("::TestConstructorOverloads::constructor::foo", "foo", "Object", False, False)]),
|
||||||
("TestConstructorOverloads",
|
("TestConstructorOverloads (Wrapper)",
|
||||||
[("::TestConstructorOverloads::constructor::bar", "bar", "Boolean", False, False)])])
|
[("::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")
|
harness.check(len(signatures), 1, "Expect one signature")
|
||||||
|
|
||||||
(returnType, arguments) = signatures[0]
|
(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")
|
harness.check(len(arguments), 1, "Method has the right number of arguments")
|
||||||
arg = arguments[0]
|
arg = arguments[0]
|
||||||
harness.ok(isinstance(arg, WebIDL.IDLArgument), "Should be an IDLArgument")
|
harness.ok(isinstance(arg, WebIDL.IDLArgument), "Should be an IDLArgument")
|
||||||
|
@ -58,4 +58,4 @@ def WebIDLTest(parser, harness):
|
||||||
"Attr has correct QName")
|
"Attr has correct QName")
|
||||||
harness.check(attr.identifier.name, "foo", "Attr has correct name")
|
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)
|
Загрузка…
Ссылка в новой задаче