mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
auto merge of #1689 : jdm/servo/unions, r=kmcallister
Seven hours on a train without internet will do this to you. Fixes #541.
This commit is contained in:
commit
df993fdaf3
10 changed files with 631 additions and 63 deletions
|
@ -92,9 +92,13 @@ class CastableObjectUnwrapper():
|
||||||
|
|
||||||
codeOnFailure is the code to run if unwrapping fails.
|
codeOnFailure is the code to run if unwrapping fails.
|
||||||
"""
|
"""
|
||||||
def __init__(self, descriptor, source, target, codeOnFailure, isOptional=False):
|
def __init__(self, descriptor, source, target, codeOnFailure, isOptional=False,
|
||||||
|
preUnwrapped=None, postUnwrapped=None):
|
||||||
assert descriptor.castable
|
assert descriptor.castable
|
||||||
|
|
||||||
|
unwrappedVal = "val"
|
||||||
|
if preUnwrapped or postUnwrapped:
|
||||||
|
unwrappedVal = preUnwrapped + unwrappedVal + postUnwrapped
|
||||||
self.substitution = { "type" : descriptor.nativeType,
|
self.substitution = { "type" : descriptor.nativeType,
|
||||||
"depth": descriptor.interface.inheritanceDepth(),
|
"depth": descriptor.interface.inheritanceDepth(),
|
||||||
"prototype": "PrototypeList::id::" + descriptor.name,
|
"prototype": "PrototypeList::id::" + descriptor.name,
|
||||||
|
@ -102,7 +106,7 @@ class CastableObjectUnwrapper():
|
||||||
"source" : source,
|
"source" : source,
|
||||||
"target" : target,
|
"target" : target,
|
||||||
"codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure), 4).define(),
|
"codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure), 4).define(),
|
||||||
"unwrapped_val" : "Some(val)" if isOptional else "val",
|
"unwrapped_val" : ("Some(%s)" % unwrappedVal) if isOptional else unwrappedVal,
|
||||||
"unwrapFn": "unwrap_jsmanaged" if 'JS' in descriptor.nativeType else "unwrap_object"}
|
"unwrapFn": "unwrap_jsmanaged" if 'JS' in descriptor.nativeType else "unwrap_object"}
|
||||||
if descriptor.hasXPConnectImpls:
|
if descriptor.hasXPConnectImpls:
|
||||||
# We don't use xpc_qsUnwrapThis because it will always throw on
|
# We don't use xpc_qsUnwrapThis because it will always throw on
|
||||||
|
@ -447,7 +451,9 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
||||||
isClamp=False,
|
isClamp=False,
|
||||||
exceptionCode=None,
|
exceptionCode=None,
|
||||||
isCallbackReturnValue=False,
|
isCallbackReturnValue=False,
|
||||||
sourceDescription="value"):
|
sourceDescription="value",
|
||||||
|
preSuccess=None,
|
||||||
|
postSuccess=None):
|
||||||
"""
|
"""
|
||||||
Get a template for converting a JS value to a native object based on the
|
Get a template for converting a JS value to a native object based on the
|
||||||
given type and descriptor. If failureCode is given, then we're actually
|
given type and descriptor. If failureCode is given, then we're actually
|
||||||
|
@ -706,8 +712,8 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
(isinstance(defaultValue, IDLNullValue) and nullable))
|
(isinstance(defaultValue, IDLNullValue) and nullable))
|
||||||
|
|
||||||
unionArgumentObj = "${holderName}"
|
unionArgumentObj = "${holderName}"
|
||||||
if isOptional or nullable:
|
#if isOptional or nullable:
|
||||||
unionArgumentObj += ".ref()"
|
# unionArgumentObj += ".get_mut_ref()"
|
||||||
|
|
||||||
memberTypes = type.flatMemberTypes
|
memberTypes = type.flatMemberTypes
|
||||||
names = []
|
names = []
|
||||||
|
@ -720,7 +726,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
name = memberType.inner.identifier.name
|
name = memberType.inner.identifier.name
|
||||||
else:
|
else:
|
||||||
name = memberType.name
|
name = memberType.name
|
||||||
interfaceObject.append(CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext" % (unionArgumentObj, name)))
|
interfaceObject.append(CGGeneric("{res = %s.TrySetTo%s(cx, ${val}, ${valPtr}); res.is_err() || !res.unwrap()}" % (unionArgumentObj, name)))
|
||||||
names.append(name)
|
names.append(name)
|
||||||
interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"), pre="done = ", post=";\n", reindent=True)
|
interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"), pre="done = ", post=";\n", reindent=True)
|
||||||
else:
|
else:
|
||||||
|
@ -731,7 +737,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
assert len(arrayObjectMemberTypes) == 1
|
assert len(arrayObjectMemberTypes) == 1
|
||||||
memberType = arrayObjectMemberTypes[0]
|
memberType = arrayObjectMemberTypes[0]
|
||||||
name = memberType.name
|
name = memberType.name
|
||||||
arrayObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
|
arrayObject = CGGeneric("done = {res = %s.TrySetTo%s(cx, ${val}, ${valPtr}); res.is_err() || !res.unwrap()};" % (unionArgumentObj, name))
|
||||||
# XXX Now we're supposed to check for an array or a platform object
|
# XXX Now we're supposed to check for an array or a platform object
|
||||||
# that supports indexed properties... skip that last for now. It's a
|
# that supports indexed properties... skip that last for now. It's a
|
||||||
# bit of a pain.
|
# bit of a pain.
|
||||||
|
@ -761,7 +767,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
assert len(callbackMemberTypes) == 1
|
assert len(callbackMemberTypes) == 1
|
||||||
memberType = callbackMemberTypes[0]
|
memberType = callbackMemberTypes[0]
|
||||||
name = memberType.name
|
name = memberType.name
|
||||||
callbackObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
|
callbackObject = CGGeneric("done = {res = %s.TrySetTo%s(cx, ${val}, ${valPtr}); res.is_err() || !res.unwrap()};" % (unionArgumentObj, name))
|
||||||
names.append(name)
|
names.append(name)
|
||||||
else:
|
else:
|
||||||
callbackObject = None
|
callbackObject = None
|
||||||
|
@ -816,7 +822,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
if any([arrayObject, dateObject, nonPlatformObject, object]):
|
if any([arrayObject, dateObject, nonPlatformObject, object]):
|
||||||
templateBody.prepend(CGGeneric("JSObject& argObj = ${val}.toObject();"))
|
templateBody.prepend(CGGeneric("JSObject& argObj = ${val}.toObject();"))
|
||||||
templateBody = CGWrapper(CGIndenter(templateBody),
|
templateBody = CGWrapper(CGIndenter(templateBody),
|
||||||
pre="if (${val}.isObject()) {\n",
|
pre="if JSVAL_IS_OBJECT(${val}) {\n",
|
||||||
post="\n}")
|
post="\n}")
|
||||||
else:
|
else:
|
||||||
templateBody = CGGeneric()
|
templateBody = CGGeneric()
|
||||||
|
@ -831,7 +837,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
name = memberType.inner.identifier.name
|
name = memberType.inner.identifier.name
|
||||||
else:
|
else:
|
||||||
name = memberType.name
|
name = memberType.name
|
||||||
other = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
|
other = CGGeneric("done = {res = %s.TrySetTo%s(cx, ${val}, ${valPtr}); res.is_err() || !res.unwrap()};" % (unionArgumentObj, name))
|
||||||
names.append(name)
|
names.append(name)
|
||||||
if hasObjectTypes:
|
if hasObjectTypes:
|
||||||
other = CGWrapper(CGIndenter(other), "{\n", post="\n}")
|
other = CGWrapper(CGIndenter(other), "{\n", post="\n}")
|
||||||
|
@ -844,28 +850,25 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
else:
|
else:
|
||||||
other = None
|
other = None
|
||||||
|
|
||||||
templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n")
|
templateBody = CGWrapper(templateBody, pre="let mut done = false;\n"
|
||||||
throw = CGGeneric("if (failed) {\n"
|
"let mut res = Ok(true);\n")
|
||||||
" return false;\n"
|
throw = CGGeneric("if res.is_err() {\n"
|
||||||
|
" return 0;\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"if (!done) {\n"
|
"if !done {\n"
|
||||||
" return ThrowErrorMessage(cx, MSG_NOT_IN_UNION, \"%s\");\n"
|
" return throw_not_in_union(cx, \"%s\");\n"
|
||||||
"}" % ", ".join(names))
|
"}" % ", ".join(names))
|
||||||
templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}")
|
templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}")
|
||||||
|
|
||||||
typeName = type.name
|
typeName = type.name
|
||||||
argumentTypeName = typeName + "Argument"
|
argumentTypeName = typeName + "Argument"
|
||||||
if nullable:
|
if nullable:
|
||||||
typeName = "Nullable<" + typeName + " >"
|
typeName = "Option<" + typeName + " >"
|
||||||
if isOptional:
|
nonConstDecl = "${declName}"
|
||||||
nonConstDecl = "const_cast<Optional<" + typeName + " >& >(${declName})"
|
|
||||||
else:
|
|
||||||
nonConstDecl = "const_cast<" + typeName + "& >(${declName})"
|
|
||||||
typeName = "const " + typeName
|
|
||||||
|
|
||||||
def handleNull(templateBody, setToNullVar, extraConditionForNull=""):
|
def handleNull(templateBody, setToNullVar, extraConditionForNull=""):
|
||||||
null = CGGeneric("if (%s${val}.isNullOrUndefined()) {\n"
|
null = CGGeneric("if %s(RUST_JSVAL_IS_NULL(${val}) != 0 || RUST_JSVAL_IS_VOID(${val}) != 0) {\n"
|
||||||
" %s.SetNull();\n"
|
" %s = None;\n"
|
||||||
"}" % (extraConditionForNull, setToNullVar))
|
"}" % (extraConditionForNull, setToNullVar))
|
||||||
templateBody = CGWrapper(CGIndenter(templateBody), pre="{\n", post="\n}")
|
templateBody = CGWrapper(CGIndenter(templateBody), pre="{\n", post="\n}")
|
||||||
return CGList([null, templateBody], " else ")
|
return CGList([null, templateBody], " else ")
|
||||||
|
@ -878,20 +881,23 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
if isOptional:
|
if isOptional:
|
||||||
mutableDecl = nonConstDecl + ".Value()"
|
mutableDecl = nonConstDecl + ".Value()"
|
||||||
declType = CGWrapper(declType, pre="const Optional<", post=" >")
|
declType = CGWrapper(declType, pre="const Optional<", post=" >")
|
||||||
holderType = CGWrapper(holderType, pre="Maybe<", post=" >")
|
holderType = CGWrapper(holderType, pre="Option<", post=" >")
|
||||||
constructDecl = CGGeneric(nonConstDecl + ".Construct();")
|
constructDecl = CGGeneric(nonConstDecl + ".Construct();")
|
||||||
if nullable:
|
if nullable:
|
||||||
constructHolder = CGGeneric("${holderName}.construct(%s.SetValue());" % mutableDecl)
|
constructHolder = CGGeneric("${holderName} = Some(%s.SetValue());" % mutableDecl)
|
||||||
else:
|
else:
|
||||||
constructHolder = CGGeneric("${holderName}.construct(${declName}.Value());")
|
constructHolder = CGGeneric("${holderName} = Some(${declName}.Value());")
|
||||||
else:
|
else:
|
||||||
mutableDecl = nonConstDecl
|
mutableDecl = nonConstDecl
|
||||||
constructDecl = None
|
constructDecl = None
|
||||||
|
holderInit = "${declName}"
|
||||||
if nullable:
|
if nullable:
|
||||||
holderType = CGWrapper(holderType, pre="Maybe<", post=" >")
|
holderInit += ".get_mut_ref()"
|
||||||
constructHolder = CGGeneric("${holderName}.construct(%s.SetValue());" % mutableDecl)
|
|
||||||
else:
|
else:
|
||||||
constructHolder = CGWrapper(holderType, post=" ${holderName}(${declName});")
|
holderInit = "&mut " + holderInit
|
||||||
|
constructHolder = CGWrapper(holderType, pre="let mut ${holderName} = ", post="::new(" + holderInit + ");")
|
||||||
|
if nullable:
|
||||||
|
constructHolder = CGWrapper(constructHolder, pre="${declName} = Some(uninit());\n")
|
||||||
holderType = None
|
holderType = None
|
||||||
|
|
||||||
templateBody = CGList([constructHolder, templateBody], "\n")
|
templateBody = CGList([constructHolder, templateBody], "\n")
|
||||||
|
@ -903,9 +909,10 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
valueMissing = ""
|
valueMissing = ""
|
||||||
templateBody = handleNull(templateBody, mutableDecl,
|
templateBody = handleNull(templateBody, mutableDecl,
|
||||||
extraConditionForNull=valueMissing)
|
extraConditionForNull=valueMissing)
|
||||||
templateBody = CGList([constructDecl, templateBody], "\n")
|
templateBody = CGWrapper(CGIndenter(CGList([constructDecl, templateBody], "\n")),
|
||||||
|
pre="{\n", post="\n}")
|
||||||
|
|
||||||
return templateBody.define(), declType, holderType, False, None
|
return templateBody.define(), declType, holderType, False, "uninit()" if not nullable else None
|
||||||
|
|
||||||
if type.isGeckoInterface():
|
if type.isGeckoInterface():
|
||||||
assert not isEnforceRange and not isClamp
|
assert not isEnforceRange and not isClamp
|
||||||
|
@ -968,7 +975,8 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
"JSVAL_TO_OBJECT(${val})",
|
"JSVAL_TO_OBJECT(${val})",
|
||||||
"${declName}",
|
"${declName}",
|
||||||
failureCode,
|
failureCode,
|
||||||
isOptional or argIsPointer or type.nullable()))
|
isOptional or argIsPointer or type.nullable(),
|
||||||
|
preUnwrapped=preSuccess, postUnwrapped=postSuccess))
|
||||||
else:
|
else:
|
||||||
templateBody += str(FailureFatalCastableObjectUnwrapper(
|
templateBody += str(FailureFatalCastableObjectUnwrapper(
|
||||||
descriptor,
|
descriptor,
|
||||||
|
@ -1254,32 +1262,41 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
elif isClamp:
|
elif isClamp:
|
||||||
conversionBehavior = "eClamp"
|
conversionBehavior = "eClamp"
|
||||||
|
|
||||||
|
if failureCode is None:
|
||||||
|
failureCode = 'return 0'
|
||||||
|
|
||||||
if type.nullable():
|
if type.nullable():
|
||||||
dataLoc = "${declName}.SetValue()"
|
dataLoc = "${declName}.SetValue()"
|
||||||
nullCondition = "(RUST_JSVAL_IS_NULL(${val}) != 0 || RUST_JSVAL_IS_VOID(${val}) != 0)"
|
nullCondition = "(RUST_JSVAL_IS_NULL(${val}) != 0 || RUST_JSVAL_IS_VOID(${val}) != 0)"
|
||||||
if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
|
if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
|
||||||
nullCondition = "!(${haveValue}) || " + nullCondition
|
nullCondition = "!(${haveValue}) || " + nullCondition
|
||||||
|
successVal = "val_"
|
||||||
|
if preSuccess or postSuccess:
|
||||||
|
successVal = preSuccess + successVal + postSuccess
|
||||||
#XXXjdm support conversionBehavior here
|
#XXXjdm support conversionBehavior here
|
||||||
template = (
|
template = (
|
||||||
"if (%s) {\n"
|
"if (%s) {\n"
|
||||||
" ${declName} = None;\n"
|
" ${declName} = None;\n"
|
||||||
"} else {\n"
|
"} else {\n"
|
||||||
" match JSValConvertible::from_jsval(${val}) {\n"
|
" match JSValConvertible::from_jsval(${val}) {\n"
|
||||||
" Some(val_) => ${declName} = Some(val_),\n"
|
" Some(val_) => ${declName} = Some(%s),\n"
|
||||||
" None => return 0\n"
|
" None => %s\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"}" % nullCondition)
|
"}" % (nullCondition, successVal, failureCode))
|
||||||
declType = CGGeneric("Option<" + typeName + ">")
|
declType = CGGeneric("Option<" + typeName + ">")
|
||||||
else:
|
else:
|
||||||
assert(defaultValue is None or
|
assert(defaultValue is None or
|
||||||
not isinstance(defaultValue, IDLNullValue))
|
not isinstance(defaultValue, IDLNullValue))
|
||||||
dataLoc = "${declName}"
|
dataLoc = "${declName}"
|
||||||
#XXXjdm conversionBehavior should be used
|
#XXXjdm conversionBehavior should be used
|
||||||
|
successVal = "v"
|
||||||
|
if preSuccess or postSuccess:
|
||||||
|
successVal = preSuccess + successVal + postSuccess
|
||||||
template = (
|
template = (
|
||||||
"match JSValConvertible::from_jsval(${val}) {\n"
|
"match JSValConvertible::from_jsval(${val}) {\n"
|
||||||
" None => return 0,\n"
|
" None => %s,\n"
|
||||||
" Some(v) => %s = v\n"
|
" Some(v) => %s = %s\n"
|
||||||
"}" % (dataLoc,))
|
"}" % (failureCode, dataLoc, successVal))
|
||||||
declType = CGGeneric(typeName)
|
declType = CGGeneric(typeName)
|
||||||
if (defaultValue is not None and
|
if (defaultValue is not None and
|
||||||
# We already handled IDLNullValue, so just deal with the other ones
|
# We already handled IDLNullValue, so just deal with the other ones
|
||||||
|
@ -2385,6 +2402,112 @@ class CGGeneric(CGThing):
|
||||||
def define(self):
|
def define(self):
|
||||||
return self.defineText
|
return self.defineText
|
||||||
|
|
||||||
|
def getTypes(descriptor):
|
||||||
|
"""
|
||||||
|
Get all argument and return types for all members of the descriptor
|
||||||
|
"""
|
||||||
|
members = [m for m in descriptor.interface.members]
|
||||||
|
if descriptor.interface.ctor():
|
||||||
|
members.append(descriptor.interface.ctor())
|
||||||
|
signatures = [s for m in members if m.isMethod() for s in m.signatures()]
|
||||||
|
types = []
|
||||||
|
for s in signatures:
|
||||||
|
assert len(s) == 2
|
||||||
|
(returnType, arguments) = s
|
||||||
|
types.append(returnType)
|
||||||
|
types.extend([a.type for a in arguments])
|
||||||
|
|
||||||
|
types.extend(a.type for a in members if a.isAttr())
|
||||||
|
return types
|
||||||
|
|
||||||
|
def SortedTuples(l):
|
||||||
|
"""
|
||||||
|
Sort a list of tuples based on the first item in the tuple
|
||||||
|
"""
|
||||||
|
return sorted(l, key=operator.itemgetter(0))
|
||||||
|
|
||||||
|
def SortedDictValues(d):
|
||||||
|
"""
|
||||||
|
Returns a list of values from the dict sorted by key.
|
||||||
|
"""
|
||||||
|
# Create a list of tuples containing key and value, sorted on key.
|
||||||
|
d = SortedTuples(d.items())
|
||||||
|
# We're only interested in the values.
|
||||||
|
return (i[1] for i in d)
|
||||||
|
|
||||||
|
def UnionTypes(descriptors):
|
||||||
|
"""
|
||||||
|
Returns a tuple containing a set of header filenames to include, a set of
|
||||||
|
tuples containing a type declaration and a boolean if the type is a struct
|
||||||
|
for member types of the unions and a CGList containing CGUnionStructs for
|
||||||
|
every union.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Now find all the things we'll need as arguments and return values because
|
||||||
|
# we need to wrap or unwrap them.
|
||||||
|
headers = set()
|
||||||
|
declarations = set()
|
||||||
|
unionStructs = dict()
|
||||||
|
for d in descriptors:
|
||||||
|
if d.interface.isExternal():
|
||||||
|
continue
|
||||||
|
|
||||||
|
for t in getTypes(d):
|
||||||
|
t = t.unroll()
|
||||||
|
if t.isUnion():
|
||||||
|
name = str(t)
|
||||||
|
if not name in unionStructs:
|
||||||
|
unionStructs[name] = CGUnionStruct(t, d)
|
||||||
|
for f in t.flatMemberTypes:
|
||||||
|
f = f.unroll()
|
||||||
|
if f.isInterface():
|
||||||
|
if f.isSpiderMonkeyInterface():
|
||||||
|
headers.add("jsfriendapi.h")
|
||||||
|
headers.add("mozilla/dom/TypedArray.h")
|
||||||
|
else:
|
||||||
|
typeDesc = d.getDescriptor(f.inner.identifier.name)
|
||||||
|
if typeDesc is not None:
|
||||||
|
declarations.add((typeDesc.nativeType, False))
|
||||||
|
elif f.isDictionary():
|
||||||
|
declarations.add((f.inner.identifier.name, True))
|
||||||
|
|
||||||
|
return (headers, declarations, CGList(SortedDictValues(unionStructs), "\n"))
|
||||||
|
|
||||||
|
def UnionConversions(descriptors):
|
||||||
|
"""
|
||||||
|
Returns a CGThing to declare all union argument conversion helper structs.
|
||||||
|
"""
|
||||||
|
# Now find all the things we'll need as arguments because we
|
||||||
|
# need to unwrap them.
|
||||||
|
unionConversions = dict()
|
||||||
|
for d in descriptors:
|
||||||
|
if d.interface.isExternal():
|
||||||
|
continue
|
||||||
|
|
||||||
|
def addUnionTypes(type):
|
||||||
|
if type.isUnion():
|
||||||
|
type = type.unroll()
|
||||||
|
name = str(type)
|
||||||
|
if not name in unionConversions:
|
||||||
|
unionConversions[name] = CGUnionConversionStruct(type, d)
|
||||||
|
|
||||||
|
members = [m for m in d.interface.members]
|
||||||
|
if d.interface.ctor():
|
||||||
|
members.append(d.interface.ctor())
|
||||||
|
signatures = [s for m in members if m.isMethod() for s in m.signatures()]
|
||||||
|
for s in signatures:
|
||||||
|
assert len(s) == 2
|
||||||
|
(_, arguments) = s
|
||||||
|
for a in arguments:
|
||||||
|
addUnionTypes(a.type)
|
||||||
|
|
||||||
|
for m in members:
|
||||||
|
if m.isAttr() and not m.readonly:
|
||||||
|
addUnionTypes(m.type)
|
||||||
|
|
||||||
|
return CGWrapper(CGList(SortedDictValues(unionConversions), "\n"),
|
||||||
|
post="\n\n")
|
||||||
|
|
||||||
class Argument():
|
class Argument():
|
||||||
"""
|
"""
|
||||||
A class for outputting the type and name of an argument
|
A class for outputting the type and name of an argument
|
||||||
|
@ -3544,6 +3667,282 @@ class CGEnum(CGThing):
|
||||||
""" % (",\n ".join(map(getEnumValueName, self.enum.values())),
|
""" % (",\n ".join(map(getEnumValueName, self.enum.values())),
|
||||||
",\n ".join(['EnumEntry {value: &"' + val + '", length: ' + str(len(val)) + '}' for val in self.enum.values()]))
|
",\n ".join(['EnumEntry {value: &"' + val + '", length: ' + str(len(val)) + '}' for val in self.enum.values()]))
|
||||||
|
|
||||||
|
def getUnionAccessorSignatureType(type, descriptorProvider):
|
||||||
|
"""
|
||||||
|
Returns the types that are used in the getter and setter signatures for
|
||||||
|
union types
|
||||||
|
"""
|
||||||
|
if type.isArray():
|
||||||
|
raise TypeError("Can't handle array arguments yet")
|
||||||
|
|
||||||
|
if type.isSequence():
|
||||||
|
nullable = type.nullable();
|
||||||
|
if nullable:
|
||||||
|
type = type.inner.inner
|
||||||
|
else:
|
||||||
|
type = type.inner
|
||||||
|
(elementTemplate, elementDeclType,
|
||||||
|
elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate(
|
||||||
|
type, descriptorProvider, isSequenceMember=True)
|
||||||
|
typeName = CGWrapper(elementDeclType, pre="Sequence< ", post=" >&")
|
||||||
|
if nullable:
|
||||||
|
typeName = CGWrapper(typeName, pre="Nullable< ", post=" >&")
|
||||||
|
|
||||||
|
return typeName
|
||||||
|
|
||||||
|
if type.isUnion():
|
||||||
|
typeName = CGGeneric(type.name)
|
||||||
|
if type.nullable():
|
||||||
|
typeName = CGWrapper(typeName, pre="Nullable< ", post=" >&")
|
||||||
|
|
||||||
|
return typeName
|
||||||
|
|
||||||
|
if type.isGeckoInterface():
|
||||||
|
descriptor = descriptorProvider.getDescriptor(
|
||||||
|
type.unroll().inner.identifier.name)
|
||||||
|
typeName = CGGeneric(descriptor.nativeType)
|
||||||
|
# Allow null pointers for nullable types and old-binding classes
|
||||||
|
if type.nullable() or type.unroll().inner.isExternal():
|
||||||
|
typeName = CGWrapper(typeName, pre="Option<", post=">")
|
||||||
|
else:
|
||||||
|
typeName = CGWrapper(typeName, pre="&'a ")
|
||||||
|
return typeName
|
||||||
|
|
||||||
|
if type.isSpiderMonkeyInterface():
|
||||||
|
typeName = CGGeneric(type.name)
|
||||||
|
if type.nullable():
|
||||||
|
typeName = CGWrapper(typeName, pre="Option<", post=">")
|
||||||
|
else:
|
||||||
|
typeName = CGWrapper(typeName, pre="&")
|
||||||
|
return typeName
|
||||||
|
|
||||||
|
if type.isString():
|
||||||
|
return CGGeneric("const nsAString&")
|
||||||
|
|
||||||
|
if type.isEnum():
|
||||||
|
if type.nullable():
|
||||||
|
raise TypeError("We don't support nullable enumerated arguments or "
|
||||||
|
"union members yet")
|
||||||
|
return CGGeneric(type.inner.identifier.name)
|
||||||
|
|
||||||
|
if type.isCallback():
|
||||||
|
return CGGeneric("JSObject*")
|
||||||
|
|
||||||
|
if type.isAny():
|
||||||
|
return CGGeneric("JS::Value")
|
||||||
|
|
||||||
|
if type.isObject():
|
||||||
|
typeName = CGGeneric("JSObject")
|
||||||
|
if type.nullable():
|
||||||
|
typeName = CGWrapper(typeName, post="*")
|
||||||
|
else:
|
||||||
|
typeName = CGWrapper(typeName, post="&")
|
||||||
|
return typeName
|
||||||
|
|
||||||
|
if not type.isPrimitive():
|
||||||
|
raise TypeError("Need native type for argument type '%s'" % str(type))
|
||||||
|
|
||||||
|
typeName = CGGeneric(builtinNames[type.tag()])
|
||||||
|
if type.nullable():
|
||||||
|
typeName = CGWrapper(typeName, pre="Nullable< ", post=" >&")
|
||||||
|
return typeName
|
||||||
|
|
||||||
|
def getUnionTypeTemplateVars(type, descriptorProvider):
|
||||||
|
# For dictionaries and sequences we need to pass None as the failureCode
|
||||||
|
# for getJSToNativeConversionTemplate.
|
||||||
|
# Also, for dictionaries we would need to handle conversion of
|
||||||
|
# null/undefined to the dictionary correctly.
|
||||||
|
if type.isDictionary() or type.isSequence():
|
||||||
|
raise TypeError("Can't handle dictionaries or sequences in unions")
|
||||||
|
|
||||||
|
if type.isGeckoInterface():
|
||||||
|
name = type.inner.identifier.name
|
||||||
|
typeName = descriptorProvider.getDescriptor(name).nativeType
|
||||||
|
elif type.isEnum():
|
||||||
|
name = type.inner.identifier.name
|
||||||
|
typeName = name
|
||||||
|
elif type.isArray() or type.isSequence():
|
||||||
|
name = str(type)
|
||||||
|
#XXXjdm dunno about typeName here
|
||||||
|
typeName = "/*" + type.name + "*/"
|
||||||
|
elif type.isPrimitive():
|
||||||
|
name = type.name
|
||||||
|
typeName = builtinNames[type.tag()]
|
||||||
|
else:
|
||||||
|
name = type.name
|
||||||
|
typeName = "/*" + type.name + "*/"
|
||||||
|
|
||||||
|
tryNextCode = """{
|
||||||
|
return Ok(true);
|
||||||
|
}"""
|
||||||
|
(template, declType, holderType,
|
||||||
|
dealWithOptional, initialValue) = getJSToNativeConversionTemplate(
|
||||||
|
type, descriptorProvider, failureCode=tryNextCode,
|
||||||
|
isDefinitelyObject=True, isOptional=type.nullable(), preSuccess="e" + name + "(", postSuccess=")")
|
||||||
|
|
||||||
|
structType = declType.define()
|
||||||
|
externalType = getUnionAccessorSignatureType(type, descriptorProvider).define()
|
||||||
|
|
||||||
|
if type.isObject():
|
||||||
|
setter = CGGeneric("pub fn SetToObject(obj: *JSObject) {\n"
|
||||||
|
" mUnion = Some(eObject(obj));\n"
|
||||||
|
"}")
|
||||||
|
else:
|
||||||
|
jsConversion = string.Template(template).substitute(
|
||||||
|
{
|
||||||
|
"val": "value",
|
||||||
|
"valPtr": "pvalue",
|
||||||
|
"declName": "*self.mUnion",
|
||||||
|
"holderName": "m" + name + "Holder"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
jsConversion = CGWrapper(CGGeneric(jsConversion),
|
||||||
|
post="\n"
|
||||||
|
"return Ok(false);")
|
||||||
|
setter = CGWrapper(CGIndenter(jsConversion),
|
||||||
|
pre="pub fn TrySetTo" + name + "(&mut self, cx: *JSContext, value: JSVal, pvalue: *JSVal) -> Result<bool,()> {\n",
|
||||||
|
post="\n"
|
||||||
|
"}")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"name": name,
|
||||||
|
"typeName": typeName,
|
||||||
|
"structType": structType,
|
||||||
|
"externalType": externalType,
|
||||||
|
"optRef": 'ref ' if externalType[0] == '&' else '',
|
||||||
|
"setter": CGIndenter(setter).define(),
|
||||||
|
"holderType": holderType.define() if holderType else None
|
||||||
|
}
|
||||||
|
|
||||||
|
def mapTemplate(template, templateVarArray):
|
||||||
|
return map(lambda v: string.Template(template).substitute(v),
|
||||||
|
templateVarArray)
|
||||||
|
|
||||||
|
class CGUnionStruct(CGThing):
|
||||||
|
def __init__(self, type, descriptorProvider):
|
||||||
|
CGThing.__init__(self)
|
||||||
|
self.type = type.unroll()
|
||||||
|
self.descriptorProvider = descriptorProvider
|
||||||
|
|
||||||
|
def declare(self):
|
||||||
|
templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider),
|
||||||
|
self.type.flatMemberTypes)
|
||||||
|
|
||||||
|
callDestructors = []
|
||||||
|
enumValues = []
|
||||||
|
methods = []
|
||||||
|
if self.type.hasNullableType:
|
||||||
|
callDestructors.append(" case eNull:\n"
|
||||||
|
" break;")
|
||||||
|
enumValues.append("eNull")
|
||||||
|
methods.append(""" pub fn IsNull(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
eNull => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}""")
|
||||||
|
|
||||||
|
destructorTemplate = """ fn Destroy${name}(&mut self) {
|
||||||
|
assert!(Is${name}(), "Wrong type!");
|
||||||
|
*self.mUnion = None;
|
||||||
|
}"""
|
||||||
|
destructors = mapTemplate(destructorTemplate, templateVars)
|
||||||
|
callDestructors.extend(mapTemplate(" case e${name}:\n"
|
||||||
|
" Destroy${name}();\n"
|
||||||
|
" break;", templateVars))
|
||||||
|
enumValues.extend(mapTemplate("e${name}(${typeName})", templateVars))
|
||||||
|
methodTemplate = """ pub fn Is${name}(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
e${name}(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn GetAs${name}<'a>(&'a self) -> ${externalType} {
|
||||||
|
assert!(self.Is${name}());
|
||||||
|
match *self {
|
||||||
|
e${name}(${optRef}inner) => inner,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
methods.extend(mapTemplate(methodTemplate, templateVars))
|
||||||
|
values = mapTemplate("UnionMember<${structType} > m${name};", templateVars)
|
||||||
|
return string.Template("""
|
||||||
|
pub enum ${structName} {
|
||||||
|
${enumValues}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ${structName} {
|
||||||
|
${methods}
|
||||||
|
}
|
||||||
|
""").substitute(
|
||||||
|
{
|
||||||
|
"structName": self.type.__str__(),
|
||||||
|
"callDestructors": "\n".join(callDestructors),
|
||||||
|
"destructors": "\n".join(destructors),
|
||||||
|
"methods": "\n\n".join(methods),
|
||||||
|
"enumValues": ",\n ".join(enumValues),
|
||||||
|
"values": "\n ".join(values),
|
||||||
|
})
|
||||||
|
|
||||||
|
def define(self):
|
||||||
|
return """
|
||||||
|
"""
|
||||||
|
|
||||||
|
class CGUnionConversionStruct(CGThing):
|
||||||
|
def __init__(self, type, descriptorProvider):
|
||||||
|
CGThing.__init__(self)
|
||||||
|
self.type = type.unroll()
|
||||||
|
self.descriptorProvider = descriptorProvider
|
||||||
|
|
||||||
|
def declare(self):
|
||||||
|
setters = []
|
||||||
|
|
||||||
|
if self.type.hasNullableType:
|
||||||
|
setters.append(""" pub fn SetNull(&mut self) -> bool
|
||||||
|
{
|
||||||
|
mUnion = Some(eNull);
|
||||||
|
return true;
|
||||||
|
}""")
|
||||||
|
|
||||||
|
templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider),
|
||||||
|
self.type.flatMemberTypes)
|
||||||
|
structName = self.type.__str__()
|
||||||
|
|
||||||
|
setters.extend(mapTemplate("${setter}", templateVars))
|
||||||
|
private = "\n".join(mapTemplate(""" fn SetAs${name}() -> &${structType}
|
||||||
|
{
|
||||||
|
mUnion.mType = mUnion.e${name};
|
||||||
|
return mUnion.mValue.m${name}.SetValue();
|
||||||
|
}""", templateVars))
|
||||||
|
private += "\n\n"
|
||||||
|
holders = filter(lambda v: v["holderType"] is not None, templateVars)
|
||||||
|
if len(holders) > 0:
|
||||||
|
private += "\n".join(mapTemplate(" ${holderType} m${name}Holder;", holders))
|
||||||
|
private += "\n\n"
|
||||||
|
private += " " + structName + "& mUnion;"
|
||||||
|
return string.Template("""
|
||||||
|
pub struct ${structName}Argument<'a> {
|
||||||
|
mUnion: &'a mut ${innerType}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ${structName}Argument<'a> {
|
||||||
|
pub fn new(union: &'a mut ${innerType}) -> ${structName}Argument<'a> {
|
||||||
|
${structName}Argument {
|
||||||
|
mUnion: union
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${setters}
|
||||||
|
}
|
||||||
|
""").substitute({"structName": structName,
|
||||||
|
"innerType": ("Option<%s>" % structName) if self.type.nullable() else structName,
|
||||||
|
"setters": "\n\n".join(setters),
|
||||||
|
})
|
||||||
|
|
||||||
|
def define(self):
|
||||||
|
return """
|
||||||
|
"""
|
||||||
|
|
||||||
class ClassItem:
|
class ClassItem:
|
||||||
""" Use with CGClass """
|
""" Use with CGClass """
|
||||||
def __init__(self, name, visibility):
|
def __init__(self, name, visibility):
|
||||||
|
@ -5169,6 +5568,8 @@ class CGBindingRoot(CGThing):
|
||||||
'dom::bindings::callback::*',
|
'dom::bindings::callback::*',
|
||||||
'dom::bindings::conversions::*',
|
'dom::bindings::conversions::*',
|
||||||
'dom::bindings::codegen::*', #XXXjdm
|
'dom::bindings::codegen::*', #XXXjdm
|
||||||
|
'dom::bindings::codegen::UnionTypes::*', #XXXjdm
|
||||||
|
'dom::bindings::codegen::UnionConversions::*', #XXXjdm
|
||||||
'script_task::{JSPageInfo, page_from_context}',
|
'script_task::{JSPageInfo, page_from_context}',
|
||||||
'dom::bindings::proxyhandler',
|
'dom::bindings::proxyhandler',
|
||||||
'dom::bindings::proxyhandler::*',
|
'dom::bindings::proxyhandler::*',
|
||||||
|
@ -5180,6 +5581,7 @@ class CGBindingRoot(CGThing):
|
||||||
'std::vec',
|
'std::vec',
|
||||||
'std::str',
|
'std::str',
|
||||||
'std::num',
|
'std::num',
|
||||||
|
'std::unstable::intrinsics::uninit',
|
||||||
'std::unstable::raw::Box',
|
'std::unstable::raw::Box',
|
||||||
],
|
],
|
||||||
[],
|
[],
|
||||||
|
@ -6254,3 +6656,89 @@ class GlobalGenRoots():
|
||||||
curr = CGList(allprotos)
|
curr = CGList(allprotos)
|
||||||
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
|
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
|
||||||
return curr
|
return curr
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def UnionTypes(config):
|
||||||
|
|
||||||
|
(includes, declarations, unions) = UnionTypes(config.getDescriptors())
|
||||||
|
includes.add("mozilla/dom/BindingUtils.h")
|
||||||
|
|
||||||
|
# Wrap all of that in our namespaces.
|
||||||
|
#curr = CGNamespace.build(['mozilla', 'dom'], unions, public=True)
|
||||||
|
curr = unions
|
||||||
|
|
||||||
|
curr = CGWrapper(curr, post='\n')
|
||||||
|
|
||||||
|
namespaces = []
|
||||||
|
stack = [CGList([])]
|
||||||
|
for (clazz, isStruct) in SortedTuples(declarations):
|
||||||
|
elements = clazz.split("::")
|
||||||
|
elements.pop()
|
||||||
|
#clazz = CGClassForwardDeclare(elements.pop(), isStruct=isStruct)
|
||||||
|
i = 0
|
||||||
|
if len(elements) > 0:
|
||||||
|
common = min(len(namespaces), len(elements))
|
||||||
|
while i < common and namespaces[i] == elements[i]:
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# pop all the namespaces that should be closed
|
||||||
|
namespaces = namespaces[:i]
|
||||||
|
|
||||||
|
# add all the namespaces that should be opened
|
||||||
|
for j, namespace in enumerate(elements[i:]):
|
||||||
|
namespaces.append(namespace)
|
||||||
|
# every CGNamespace that we add holds a CGList
|
||||||
|
list = CGList([])
|
||||||
|
# add the new namespace to the list on top of the stack
|
||||||
|
stack[i + j].append(CGNamespace(namespace, list))
|
||||||
|
# set the top of the namespace stack to the list of the new
|
||||||
|
# namespace
|
||||||
|
stack[i + j + 1:] = [list]
|
||||||
|
|
||||||
|
#stack[len(elements)].append(clazz)
|
||||||
|
|
||||||
|
curr = CGList([stack[0], curr], "\n")
|
||||||
|
|
||||||
|
#curr = CGHeaders([], [], includes, [], curr)
|
||||||
|
|
||||||
|
# Add include guards.
|
||||||
|
#curr = CGIncludeGuard('UnionTypes', curr)
|
||||||
|
|
||||||
|
curr = CGImports([], [], ['dom::bindings::js::JS',
|
||||||
|
'dom::types::*'], [], curr)
|
||||||
|
|
||||||
|
# Add the auto-generated comment.
|
||||||
|
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
|
||||||
|
|
||||||
|
# Done.
|
||||||
|
return curr
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def UnionConversions(config):
|
||||||
|
|
||||||
|
unions = UnionConversions(config.getDescriptors())
|
||||||
|
curr = unions
|
||||||
|
|
||||||
|
# Wrap all of that in our namespaces.
|
||||||
|
#curr = CGNamespace.build(['mozilla', 'dom'], unions)
|
||||||
|
|
||||||
|
curr = CGWrapper(curr, post='\n')
|
||||||
|
|
||||||
|
#curr = CGHeaders([], [], ["nsDebug.h", "mozilla/dom/UnionTypes.h", "nsDOMQS.h"], [], curr)
|
||||||
|
|
||||||
|
# Add include guards.
|
||||||
|
#curr = CGIncludeGuard('UnionConversions', curr)
|
||||||
|
|
||||||
|
curr = CGImports([], [], ['dom::bindings::utils::unwrap_jsmanaged',
|
||||||
|
'dom::bindings::codegen::UnionTypes::*',
|
||||||
|
'dom::bindings::codegen::PrototypeList',
|
||||||
|
'dom::bindings::conversions::JSValConvertible',
|
||||||
|
'js::*',
|
||||||
|
'js::jsapi::*',
|
||||||
|
'js::glue::*'], [], curr)
|
||||||
|
|
||||||
|
# Add the auto-generated comment.
|
||||||
|
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
|
||||||
|
|
||||||
|
# Done.
|
||||||
|
return curr
|
||||||
|
|
|
@ -89,9 +89,8 @@ def main():
|
||||||
# Generate the module declarations.
|
# Generate the module declarations.
|
||||||
generate_file(config, 'BindingDeclarations', 'declare+define')
|
generate_file(config, 'BindingDeclarations', 'declare+define')
|
||||||
|
|
||||||
#XXXjdm No union support yet
|
generate_file(config, 'UnionTypes', 'declare+define')
|
||||||
#generate_file(config, 'UnionTypes', 'declare')
|
generate_file(config, 'UnionConversions', 'declare+define')
|
||||||
#generate_file(config, 'UnionConversions', 'declare')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
use js::jsapi::JSVal;
|
use js::jsapi::JSVal;
|
||||||
use js::{JSVAL_FALSE, JSVAL_TRUE};
|
use js::{JSVAL_FALSE, JSVAL_TRUE};
|
||||||
use js::glue::{RUST_UINT_TO_JSVAL, RUST_JSVAL_TO_INT, RUST_DOUBLE_TO_JSVAL, RUST_JSVAL_TO_DOUBLE};
|
use js::glue::{RUST_UINT_TO_JSVAL, RUST_JSVAL_TO_INT, RUST_DOUBLE_TO_JSVAL};
|
||||||
|
use js::glue::{RUST_JSVAL_TO_DOUBLE, RUST_JSVAL_IS_INT, RUST_JSVAL_IS_DOUBLE};
|
||||||
|
use js::glue::{RUST_JSVAL_IS_BOOLEAN, RUST_JSVAL_TO_BOOLEAN};
|
||||||
|
|
||||||
pub trait JSValConvertible {
|
pub trait JSValConvertible {
|
||||||
fn to_jsval(&self) -> JSVal;
|
fn to_jsval(&self) -> JSVal;
|
||||||
|
@ -21,7 +23,11 @@ impl JSValConvertible for i64 {
|
||||||
|
|
||||||
fn from_jsval(val: JSVal) -> Option<i64> {
|
fn from_jsval(val: JSVal) -> Option<i64> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
if RUST_JSVAL_IS_INT(val) != 0 {
|
||||||
Some(RUST_JSVAL_TO_DOUBLE(val) as i64)
|
Some(RUST_JSVAL_TO_DOUBLE(val) as i64)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +41,11 @@ impl JSValConvertible for u32 {
|
||||||
|
|
||||||
fn from_jsval(val: JSVal) -> Option<u32> {
|
fn from_jsval(val: JSVal) -> Option<u32> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
if RUST_JSVAL_IS_INT(val) != 0 {
|
||||||
Some(RUST_JSVAL_TO_INT(val) as u32)
|
Some(RUST_JSVAL_TO_INT(val) as u32)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +59,11 @@ impl JSValConvertible for i32 {
|
||||||
|
|
||||||
fn from_jsval(val: JSVal) -> Option<i32> {
|
fn from_jsval(val: JSVal) -> Option<i32> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
if RUST_JSVAL_IS_INT(val) != 0 {
|
||||||
Some(RUST_JSVAL_TO_INT(val) as i32)
|
Some(RUST_JSVAL_TO_INT(val) as i32)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +77,11 @@ impl JSValConvertible for u16 {
|
||||||
|
|
||||||
fn from_jsval(val: JSVal) -> Option<u16> {
|
fn from_jsval(val: JSVal) -> Option<u16> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
if RUST_JSVAL_IS_INT(val) != 0 {
|
||||||
Some(RUST_JSVAL_TO_INT(val) as u16)
|
Some(RUST_JSVAL_TO_INT(val) as u16)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,15 +96,15 @@ impl JSValConvertible for bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_jsval(val: JSVal) -> Option<bool> {
|
fn from_jsval(val: JSVal) -> Option<bool> {
|
||||||
if val == JSVAL_TRUE {
|
unsafe {
|
||||||
Some(true)
|
if RUST_JSVAL_IS_BOOLEAN(val) != 0 {
|
||||||
} else if val == JSVAL_FALSE {
|
Some(RUST_JSVAL_TO_BOOLEAN(val) != 0)
|
||||||
Some(false)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl JSValConvertible for f32 {
|
impl JSValConvertible for f32 {
|
||||||
fn to_jsval(&self) -> JSVal {
|
fn to_jsval(&self) -> JSVal {
|
||||||
|
@ -97,7 +115,11 @@ impl JSValConvertible for f32 {
|
||||||
|
|
||||||
fn from_jsval(val: JSVal) -> Option<f32> {
|
fn from_jsval(val: JSVal) -> Option<f32> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
if RUST_JSVAL_IS_DOUBLE(val) != 0 {
|
||||||
Some(RUST_JSVAL_TO_DOUBLE(val) as f32)
|
Some(RUST_JSVAL_TO_DOUBLE(val) as f32)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +133,11 @@ impl JSValConvertible for f64 {
|
||||||
|
|
||||||
fn from_jsval(val: JSVal) -> Option<f64> {
|
fn from_jsval(val: JSVal) -> Option<f64> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
if RUST_JSVAL_IS_DOUBLE(val) != 0 {
|
||||||
Some(RUST_JSVAL_TO_DOUBLE(val) as f64)
|
Some(RUST_JSVAL_TO_DOUBLE(val) as f64)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -879,6 +879,15 @@ pub fn throw_method_failed_with_details<T>(cx: *JSContext,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn throw_not_in_union(cx: *JSContext, names: &'static str) -> JSBool {
|
||||||
|
assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
|
||||||
|
let message = format!("argument could not be converted to any of: {}", names);
|
||||||
|
message.with_c_str(|string| {
|
||||||
|
unsafe { ReportError(cx, string) };
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// Execute arbitrary code with the JS GC enabled, then disable it afterwards.
|
/// Execute arbitrary code with the JS GC enabled, then disable it afterwards.
|
||||||
pub fn with_gc_enabled<R>(cx: *JSContext, f: || -> R) -> R {
|
pub fn with_gc_enabled<R>(cx: *JSContext, f: || -> R) -> R {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use dom::bindings::codegen::HTMLSelectElementBinding;
|
use dom::bindings::codegen::HTMLSelectElementBinding;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLSelectElementDerived;
|
use dom::bindings::codegen::InheritTypes::HTMLSelectElementDerived;
|
||||||
|
use dom::bindings::codegen::UnionTypes::{HTMLElementOrLong, HTMLOptionElementOrHTMLOptGroupElement};
|
||||||
use dom::bindings::js::JS;
|
use dom::bindings::js::JS;
|
||||||
use dom::bindings::utils::ErrorResult;
|
use dom::bindings::utils::ErrorResult;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
|
@ -175,4 +176,8 @@ impl HTMLSelectElement {
|
||||||
|
|
||||||
pub fn SetCustomValidity(&mut self, _error: DOMString) {
|
pub fn SetCustomValidity(&mut self, _error: DOMString) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn Add(&self, _element: HTMLOptionElementOrHTMLOptGroupElement, _before: Option<HTMLElementOrLong>) -> ErrorResult {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,8 @@ interface HTMLSelectElement : HTMLElement {
|
||||||
attribute unsigned long length;
|
attribute unsigned long length;
|
||||||
getter Element? item(unsigned long index);
|
getter Element? item(unsigned long index);
|
||||||
HTMLOptionElement? namedItem(DOMString name);
|
HTMLOptionElement? namedItem(DOMString name);
|
||||||
/*[Throws]
|
[Throws]
|
||||||
void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null);*/
|
void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null);
|
||||||
void remove(long index);
|
void remove(long index);
|
||||||
[Throws]
|
[Throws]
|
||||||
setter creator void (unsigned long index, HTMLOptionElement? option);
|
setter creator void (unsigned long index, HTMLOptionElement? option);
|
||||||
|
|
|
@ -40,6 +40,8 @@ pub mod dom {
|
||||||
pub mod PrototypeList;
|
pub mod PrototypeList;
|
||||||
pub mod RegisterBindings;
|
pub mod RegisterBindings;
|
||||||
pub mod BindingDeclarations;
|
pub mod BindingDeclarations;
|
||||||
|
pub mod UnionConversions;
|
||||||
|
pub mod UnionTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,24 @@ function is_function(val, name) {
|
||||||
starts_with(String(val), "function " + name + "(");
|
starts_with(String(val), "function " + name + "(");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function should_throw(f) {
|
||||||
|
try {
|
||||||
|
f();
|
||||||
|
_fail("operation should have thrown but did not");
|
||||||
|
} catch (x) {
|
||||||
|
_pass("operation successfully threw an exception", x.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function should_not_throw(f) {
|
||||||
|
try {
|
||||||
|
f();
|
||||||
|
_pass("operation did not throw an exception");
|
||||||
|
} catch (x) {
|
||||||
|
_fail("operation should have not thrown", x.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var _test_complete = false;
|
var _test_complete = false;
|
||||||
var _test_timeout = 10000; //10 seconds
|
var _test_timeout = 10000; //10 seconds
|
||||||
function finish() {
|
function finish() {
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<script src="harness.js"></script>
|
<script src="harness.js"></script>
|
||||||
<script>
|
<script>
|
||||||
try {
|
should_throw(function() { document.createElement("1foo") });
|
||||||
document.createElement("1foo");
|
|
||||||
is(true, false, "No exception thrown");
|
|
||||||
} catch (e) {
|
|
||||||
is(true, true, "Exception caught");
|
|
||||||
}
|
|
||||||
finish();
|
finish();
|
||||||
</script>
|
</script>
|
||||||
|
|
26
src/test/html/content/test_union.html
Normal file
26
src/test/html/content/test_union.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="harness.js"></script>
|
||||||
|
<select id="sel"></select>
|
||||||
|
<script>
|
||||||
|
var div = document.createElement('div');
|
||||||
|
var optgroup = document.createElement('optgroup');
|
||||||
|
var sel = document.getElementById('sel');
|
||||||
|
|
||||||
|
should_not_throw(function() {
|
||||||
|
var opt = document.createElement('option');
|
||||||
|
sel.add(opt);
|
||||||
|
sel.add(optgroup);
|
||||||
|
sel.add(opt, div);
|
||||||
|
sel.add(optgroup, div);
|
||||||
|
sel.add(opt, 5);
|
||||||
|
sel.add(optgroup, 5);
|
||||||
|
});
|
||||||
|
|
||||||
|
should_throw(function() { sel.add(div) });
|
||||||
|
should_throw(function() { sel.add(optgroup, function() {}) });
|
||||||
|
|
||||||
|
finish();
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue