servo: Merge #2299 - Cleanup getJSToNativeConversionTemplate (from Ms2ger:getJSToNativeConversionTemplate-cleanup); r=jdm

Source-Repo: https://github.com/servo/servo
Source-Revision: f642d5951a562570cbef052c03463ef5da2777be
This commit is contained in:
Ms2ger 2014-05-05 09:43:18 -04:00
Родитель f7bf139ec7
Коммит 9263d78f5f
1 изменённых файлов: 74 добавлений и 137 удалений

Просмотреть файл

@ -281,7 +281,6 @@ class CGMethodCall(CGThing):
isDefinitelyObject=True),
{
"declName" : "arg%d" % distinguishingIndex,
"holderName" : ("arg%d" % distinguishingIndex) + "_holder",
"val" : distinguishingArg
})
@ -449,9 +448,6 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
substitution performed on it as follows:
${val} replaced by an expression for the JS::Value in question
${valPtr} is a pointer to the JS::Value in question
${holderName} replaced by the holder's name, if any
${declName} replaced by the declaration's name
${haveValue} replaced by an expression that evaluates to a boolean
for whether we have a JS::Value. Only used when
defaultValue is not None.
@ -460,15 +456,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
(declType). This is allowed to be None if the conversion code is
supposed to be used as-is.
3) A boolean indicating whether the caller has to do optional-argument handling.
This will only be true if isOptional is true and if the returned template
expects both declType and holderType to be wrapped in Optional<>, with
${declName} and ${holderName} adjusted to point to the Value() of the
Optional, and Construct() calls to be made on the Optional<>s as needed.
${declName} must be in scope before the generated code is entered.
If holderType is not None then ${holderName} must be in scope
before the generated code is entered.
"""
# If we have a defaultValue then we're not actually optional for
# purposes of what we need to be declared as.
@ -486,15 +474,18 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
needsRooting = typeNeedsRooting(type, descriptorProvider)
def handleOptional(template, declType, isOptional):
def handleOptional(template, declType, isOptional, default):
assert (defaultValue is None) == (default is None)
if isOptional:
template = "Some(%s)" % template
declType = CGWrapper(declType, pre="Option<", post=">")
initialValue = "None"
else:
initialValue = None
return (template, declType, isOptional, initialValue, needsRooting)
if default is not None:
template = CGIfElseWrapper("${haveValue}",
CGGeneric(template),
CGGeneric(default)).define()
return (template, declType, isOptional, needsRooting)
# Unfortunately, .capitalize() on a string will lowercase things inside the
# string, which we do not want.
@ -521,23 +512,17 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
exceptionCode))),
post="\n")
# A helper function for handling default values. Takes a template
# body and the C++ code to set the default value and wraps the
# given template body in handling for the default value.
def handleDefault(template, setDefault):
# A helper function for handling null default values. Checks that the
# default value, if it exists, is null.
def handleDefaultNull(nullValue):
if defaultValue is None:
return template
return CGIfElseWrapper("${haveValue}",
CGGeneric(template),
CGGeneric(setDefault)).define()
return None
# A helper function for handling null default values. Much like
# handleDefault, but checks that the default value, if it exists, is null.
def handleDefaultNull(template, codeToSetNull):
if (defaultValue is not None and
not isinstance(defaultValue, IDLNullValue)):
if not isinstance(defaultValue, IDLNullValue):
raise TypeError("Can't handle non-null default value here")
return handleDefault(template, codeToSetNull)
assert type.nullable() or type.isAny() or type.isDictionary()
return nullValue
# A helper function for wrapping up the template body for
# possibly-nullable objecty stuff
@ -557,10 +542,6 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
"} else {\n" +
CGIndenter(onFailureNotAnObject(failureCode)).define() +
"}\n")
if type.nullable():
templateBody = handleDefaultNull(templateBody, "None")
else:
assert(defaultValue is None)
return templateBody
@ -581,15 +562,12 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
if type.nullable():
declType = CGWrapper(declType, pre="Option<", post=" >")
templateBody = CGGeneric("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
" Ok(value) => value,\n"
" Err(()) => { %s },\n"
"}" % exceptionCode)
templateBody = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
" Ok(value) => value,\n"
" Err(()) => { %s },\n"
"}" % exceptionCode)
templateBody = handleDefaultNull(templateBody.define(),
"None")
return handleOptional(templateBody, declType, isOptional)
return handleOptional(templateBody, declType, isOptional, handleDefaultNull("None"))
if type.isGeckoInterface():
assert not isEnforceRange and not isClamp
@ -604,7 +582,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
template = wrapObjectTemplate(conversion, isDefinitelyObject, type,
failureCode)
return handleOptional(template, declType, isOptional)
return handleOptional(template, declType, isOptional, handleDefaultNull("None"))
descriptorType = descriptor.memberType if isMember else descriptor.nativeType
@ -634,7 +612,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
type, failureCode)
return handleOptional(templateBody, declType, isOptional)
return handleOptional(templateBody, declType, isOptional, handleDefaultNull("None"))
if type.isSpiderMonkeyInterface():
raise TypeError("Can't handle SpiderMonkey interface arguments yet")
@ -653,20 +631,19 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
else:
nullBehavior = treatAs[treatNullAs]
def getConversionCode():
conversionCode = (
"match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
" Ok(strval) => strval,\n"
" Err(_) => { %s },\n"
"}" % (nullBehavior, exceptionCode))
if defaultValue is None:
return conversionCode
if isinstance(defaultValue, IDLNullValue):
assert(type.nullable())
return handleDefault(conversionCode, "None")
conversionCode = (
"match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
" Ok(strval) => strval,\n"
" Err(_) => { %s },\n"
"}" % (nullBehavior, exceptionCode))
if defaultValue is None:
default = None
elif isinstance(defaultValue, IDLNullValue):
assert type.nullable()
default = "None"
else:
assert defaultValue.type.tag() == IDLType.Tags.domstring
value = "str::from_utf8(data).unwrap().to_owned()"
if type.nullable():
value = "Some(%s)" % value
@ -678,13 +655,11 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
", ".join(["'" + char + "' as u8" for char in defaultValue.value] + ["0"]),
value))
return handleDefault(conversionCode, default)
declType = "DOMString"
if type.nullable():
declType = "Option<%s>" % declType
return handleOptional(getConversionCode(), CGGeneric(declType), isOptional)
return handleOptional(conversionCode, CGGeneric(declType), isOptional, default)
if type.isByteString():
assert not isEnforceRange and not isClamp
@ -698,11 +673,8 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
declType = CGGeneric("ByteString")
if type.nullable():
declType = CGWrapper(declType, pre="Option<", post=">")
conversionCode = handleDefaultNull(conversionCode, "None")
else:
assert defaultValue is None
return handleOptional(conversionCode, declType, isOptional)
return handleOptional(conversionCode, declType, isOptional, handleDefaultNull("None"))
if type.isEnum():
assert not isEnforceRange and not isClamp
@ -730,12 +702,11 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
if defaultValue is not None:
assert(defaultValue.type.tag() == IDLType.Tags.domstring)
template = handleDefault(template,
("%sValues::%s" %
(enum,
getEnumValueName(defaultValue.value))))
default = "%sValues::%s" % (enum, getEnumValueName(defaultValue.value))
else:
default = None
return handleOptional(template, CGGeneric(enum), isOptional)
return handleOptional(template, CGGeneric(enum), isOptional, default)
if type.isCallback():
assert not isEnforceRange and not isClamp
@ -761,8 +732,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
assert not isEnforceRange and not isClamp
declType = CGGeneric("JSVal")
templateBody = handleDefaultNull("${val}", "NullValue()")
return handleOptional(templateBody, declType, isOptional)
return handleOptional("${val}", declType, isOptional, handleDefaultNull("NullValue()"))
if type.isObject():
raise TypeError("Can't handle object arguments yet")
@ -777,29 +747,19 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
assert not isOptional
typeName = CGDictionary.makeDictionaryName(type.inner)
declType = CGGeneric(typeName)
# We do manual default value handling here, because we
# actually do want a jsval, and we only handle null anyway
if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue))
val = "if ${haveValue} { ${val} } else { NullValue() }"
else:
val = "${val}"
template = ("match %s::new(cx, %s) {\n"
template = ("match %s::new(cx, ${val}) {\n"
" Ok(dictionary) => dictionary,\n"
" Err(_) => return 0,\n"
"}" % (typeName, val))
"}" % typeName)
return handleOptional(template, declType, isOptional)
return handleOptional(template, declType, isOptional, handleDefaultNull("%s::empty()" % typeName))
if type.isVoid():
assert not isOptional
# This one only happens for return values, and its easy: Just
# ignore the jsval.
return ("", None, False, None, False)
return ("", None, False, False)
if not type.isPrimitive():
raise TypeError("Need conversion for argument type '%s'" % str(type))
@ -834,12 +794,10 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
if type.nullable():
defaultStr = "Some(%s)" % defaultStr
else:
defaultStr = None
template = CGIfElseWrapper("${haveValue}",
CGGeneric(template),
CGGeneric(defaultStr)).define()
return handleOptional(template, declType, isOptional)
return handleOptional(template, declType, isOptional, defaultStr)
def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
argcAndIndex=None):
@ -852,7 +810,7 @@ def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
replace ${argc} and ${index}, where ${index} is the index of this
argument (0-based) and ${argc} is the total number of arguments.
"""
(templateBody, declType, dealWithOptional, initialValue, needsRooting) = templateTuple
(templateBody, declType, dealWithOptional, needsRooting) = templateTuple
if dealWithOptional and argcAndIndex is None:
raise TypeError("Have to deal with optional things, but don't know how")
@ -866,35 +824,26 @@ def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
string.Template(templateBody).substitute(replacements)
)
if declType is not None:
newDecl = [CGGeneric("let mut "),
CGGeneric(replacements["declName"]),
CGGeneric(": "),
declType]
if initialValue:
newDecl.append(CGGeneric(" = " + initialValue))
newDecl.append(CGGeneric(";"))
result.append(CGList(newDecl))
conversion = CGWrapper(conversion,
pre="%s = " % replacements["declName"],
post=";")
if argcAndIndex is not None:
declConstruct = None
holderConstruct = None
condition = string.Template("${index} < ${argc}").substitute(argcAndIndex)
conversion = CGIfElseWrapper(condition,
conversion,
CGGeneric("None"))
conversion = CGList(
[CGGeneric(
string.Template("if ${index} < ${argc} {").substitute(
argcAndIndex
)),
declConstruct,
holderConstruct,
CGIndenter(conversion),
CGGeneric("}")],
"\n")
if declType is not None:
newDecl = [
CGGeneric("let mut "),
CGGeneric(replacements["declName"]),
CGGeneric(": "),
declType,
CGGeneric(" = "),
conversion,
CGGeneric(";"),
]
result.append(CGList(newDecl))
else:
result.append(conversion)
result.append(conversion)
# Add an empty CGGeneric to get an extra newline after the argument
# conversion.
result.append(CGGeneric(""))
@ -945,13 +894,10 @@ class CGArgumentConverter(CGThing):
}
self.replacementVariables = {
"declName" : "arg%d" % index,
"holderName" : ("arg%d" % index) + "_holder"
}
self.replacementVariables["val"] = string.Template(
"(*${argv}.offset(${index}))"
).substitute(replacer)
self.replacementVariables["valPtr"] = (
"&" + self.replacementVariables["val"])
if argument.defaultValue:
self.replacementVariables["haveValue"] = string.Template(
"${index} < ${argc}").substitute(replacer)
@ -2755,7 +2701,7 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
name = type.name
typeName = "/*" + type.name + "*/"
(template, _, _, _, _) = getJSToNativeConversionTemplate(
(template, _, _, _) = getJSToNativeConversionTemplate(
type, descriptorProvider, failureCode="return Ok(None);",
exceptionCode='return Err(());',
isDefinitelyObject=True, isOptional=False)
@ -2763,8 +2709,6 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
assert not type.isObject()
jsConversion = string.Template(template).substitute({
"val": "value",
"valPtr": None,
"holderName": None,
})
jsConversion = CGWrapper(CGGeneric(jsConversion), pre="Ok(Some(", post="))")
@ -3413,9 +3357,7 @@ class CGProxySpecialOperation(CGPerSignatureCall):
treatNullAs=argument.treatNullAs)
templateValues = {
"declName": argument.identifier.name,
"holderName": argument.identifier.name + "_holder",
"val": "(*desc).value",
"valPtr": "&(*desc).value"
}
self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(template, templateValues))
elif operation.isGetter():
@ -4100,6 +4042,9 @@ class CGDictionary(CGThing):
return string.Template(
"impl<'a, 'b> ${selfName}<'a, 'b> {\n"
" pub fn empty() -> ${selfName} {\n"
" ${selfName}::new(ptr::null(), NullValue()).unwrap()\n"
" }\n"
" pub fn new(cx: *JSContext, val: JSVal) -> Result<${selfName}, ()> {\n"
" let object = if val.is_null_or_undefined() {\n"
" ptr::null()\n"
@ -4137,15 +4082,13 @@ class CGDictionary(CGThing):
return "/* uh oh */ %s" % name
def getMemberType(self, memberInfo):
(member, (templateBody, declType,
dealWithOptional, initialValue, _)) = memberInfo
(member, (templateBody, declType, dealWithOptional, _)) = memberInfo
if dealWithOptional:
declType = CGWrapper(declType, pre="Optional< ", post=" >")
return declType.define()
def getMemberConversion(self, memberInfo):
(member, (templateBody, declType,
dealWithOptional, initialValue, _)) = memberInfo
(member, (templateBody, declType, dealWithOptional, _)) = memberInfo
replacements = { "val": "value.unwrap()" }
if member.defaultValue:
replacements["haveValue"] = "value.is_some()"
@ -4400,7 +4343,7 @@ class CGNativeMember(ClassMethod):
None if isMember is true.
The third element is a template for actually returning a value stored in
"${declName}" and "${holderName}". This means actually returning it if
"${declName}". This means actually returning it if
we're not outparam, else assigning to the "retval" outparam. If
isMember is true, this can be None, since in that case the caller will
never examine this value.
@ -4922,13 +4865,7 @@ class CallbackMember(CGNativeMember):
def getResultConversion(self):
replacements = {
"val": "rval",
"mutableVal": "&rval",
"holderName" : "rvalHolder",
"declName" : "rvalDecl",
# We actually want to pass in a null scope object here, because
# wrapping things into our current compartment (that of mCallback)
# is what we want.
"obj": "nullptr"
}
if isJSImplementedDescriptor(self.descriptorProvider):