aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/codegen/CodegenRust.py
diff options
context:
space:
mode:
authorMukilan Thiyagarajan <mukilanthiagarajan@gmail.com>2014-11-08 20:55:09 +0530
committerMukilan Thiyagarajan <mukilanthiagarajan@gmail.com>2014-11-15 18:29:48 +0530
commit05bd182538a9358b2f6cee8d41696e1fd516c3d6 (patch)
tree24b2e99daa407be0044f41347ec65e51f4820303 /components/script/dom/bindings/codegen/CodegenRust.py
parent443b1b98e168f2831ff0d6526c3a00b1a05c763e (diff)
downloadservo-05bd182538a9358b2f6cee8d41696e1fd516c3d6.tar.gz
servo-05bd182538a9358b2f6cee8d41696e1fd516c3d6.zip
Fix binding generation for Callback Functions and Callback Interfaces
Diffstat (limited to 'components/script/dom/bindings/codegen/CodegenRust.py')
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py407
1 files changed, 76 insertions, 331 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index aaac17a9002..9a2cb83bcb1 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -601,11 +601,13 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
if descriptor.interface.isCallback():
name = descriptor.nativeType
- declType = CGGeneric("Option<%s>" % name);
- conversion = ("Some(%s::new((${val}).to_object()))" % name)
+ declType = CGGeneric(name)
+ template = "%s::new((${val}).to_object())" % name
+ if type.nullable():
+ declType = CGWrapper(declType, pre="Option<", post=">")
+ template = wrapObjectTemplate("Some(%s)" % template, isDefinitelyObject, type,
+ failureCode)
- template = wrapObjectTemplate(conversion, isDefinitelyObject, type,
- failureCode)
return handleOptional(template, declType, handleDefaultNull("None"))
if isMember:
@@ -983,15 +985,14 @@ class CGArgumentConverter(CGThing):
needsRooting)
seqType = CGTemplatedType("Vec", declType)
+
variadicConversion = string.Template(
- "{\n"
- " let mut vector: ${seqType} = Vec::with_capacity((${argc} - ${index}) as uint);\n"
- " for variadicArg in range(${index}, ${argc}) {\n"
+ "let mut vector: ${seqType} = Vec::with_capacity((${argc} - ${index}) as uint);\n"
+ "for variadicArg in range(${index}, ${argc}) {\n"
"${inner}\n"
" vector.push(slot);\n"
- " }\n"
- " vector\n"
- "}"
+ "}\n"
+ "vector"
).substitute({
"index": index,
"argc": argc,
@@ -999,6 +1000,10 @@ class CGArgumentConverter(CGThing):
"inner": CGIndenter(innerConverter, 4).define(),
})
+ variadicConversion = CGIfElseWrapper(condition,
+ CGGeneric(variadicConversion),
+ CGGeneric("Vec::new()")).define()
+
self.converter = instantiateJSToNativeConversionTemplate(
variadicConversion, replacementVariables, seqType, "arg%d" % index,
False)
@@ -3993,44 +3998,14 @@ class CGInterfaceTrait(CGThing):
def __init__(self, descriptor):
CGThing.__init__(self)
- def argument_type(ty, optional=False, defaultValue=None, variadic=False):
- _, _, declType, _ = getJSToNativeConversionTemplate(
- ty, descriptor, isArgument=True)
-
- if variadic:
- declType = CGWrapper(declType, pre="Vec<", post=">")
- elif optional and not defaultValue:
- declType = CGWrapper(declType, pre="Option<", post=">")
-
- if ty.isDictionary():
- declType = CGWrapper(declType, pre="&")
-
- return declType.define()
def attribute_arguments(needCx, argument=None):
if needCx:
yield "cx", "*mut JSContext"
if argument:
- yield "value", argument_type(argument)
+ yield "value", argument_type(descriptor, argument)
- def method_arguments(returnType, arguments, trailing=None):
- if needCx(returnType, arguments, True):
- yield "cx", "*mut JSContext"
-
- for argument in arguments:
- ty = argument_type(argument.type, argument.optional,
- argument.defaultValue, argument.variadic)
- yield CGDictionary.makeMemberName(argument.identifier.name), ty
-
- if trailing:
- yield trailing
-
- def return_type(rettype, infallible):
- result = getRetvalDeclarationForType(rettype, descriptor)
- if not infallible:
- result = CGWrapper(result, pre="Fallible<", post=">")
- return result.define()
def members():
for m in descriptor.interface.members:
@@ -4039,14 +4014,14 @@ class CGInterfaceTrait(CGThing):
name = CGSpecializedMethod.makeNativeName(descriptor, m)
infallible = 'infallible' in descriptor.getExtendedAttributes(m)
for idx, (rettype, arguments) in enumerate(m.signatures()):
- arguments = method_arguments(rettype, arguments)
- rettype = return_type(rettype, infallible)
+ arguments = method_arguments(descriptor, rettype, arguments)
+ rettype = return_type(descriptor, rettype, infallible)
yield name + ('_' * idx), arguments, rettype
elif m.isAttr() and not m.isStatic():
name = CGSpecializedGetter.makeNativeName(descriptor, m)
infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True)
needCx = typeNeedsCx(m.type)
- yield name, attribute_arguments(needCx), return_type(m.type, infallible)
+ yield name, attribute_arguments(needCx), return_type(descriptor, m.type, infallible)
if not m.readonly:
name = CGSpecializedSetter.makeNativeName(descriptor, m)
@@ -4067,10 +4042,10 @@ class CGInterfaceTrait(CGThing):
infallible = 'infallible' in descriptor.getExtendedAttributes(operation)
if operation.isGetter():
- arguments = method_arguments(rettype, arguments, ("found", "&mut bool"))
+ arguments = method_arguments(descriptor, rettype, arguments, trailing=("found", "&mut bool"))
else:
- arguments = method_arguments(rettype, arguments)
- rettype = return_type(rettype, infallible)
+ arguments = method_arguments(descriptor, rettype, arguments)
+ rettype = return_type(descriptor, rettype, infallible)
yield name, arguments, rettype
def fmt(arguments):
@@ -4573,6 +4548,38 @@ class CGBindingRoot(CGThing):
def define(self):
return stripTrailingWhitespace(self.root.define())
+def argument_type(descriptorProvdider, ty, optional=False, defaultValue=None, variadic=False):
+ _, _, declType, _ = getJSToNativeConversionTemplate(
+ ty, descriptorProvdider, isArgument=True)
+
+ if variadic:
+ declType = CGWrapper(declType, pre="Vec<", post=">")
+ elif optional and not defaultValue:
+ declType = CGWrapper(declType, pre="Option<", post=">")
+
+ if ty.isDictionary():
+ declType = CGWrapper(declType, pre="&")
+
+ return declType.define()
+
+def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None):
+ if needCx(returnType, arguments, passJSBits):
+ yield "cx", "*mut JSContext"
+
+ for argument in arguments:
+ ty = argument_type(descriptorProvider, argument.type, argument.optional,
+ argument.defaultValue, argument.variadic)
+ yield CGDictionary.makeMemberName(argument.identifier.name), ty
+
+ if trailing:
+ yield trailing
+
+def return_type(descriptorProvider, rettype, infallible):
+ result = getRetvalDeclarationForType(rettype, descriptorProvider)
+ if not infallible:
+ result = CGWrapper(result, pre="Fallible<", post=">")
+ return result.define()
+
class CGNativeMember(ClassMethod):
def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
@@ -4592,7 +4599,7 @@ class CGNativeMember(ClassMethod):
self.variadicIsSequence = variadicIsSequence
breakAfterSelf = "\n" if breakAfter else ""
ClassMethod.__init__(self, name,
- self.getReturnType(signature[0], False),
+ self.getReturnType(signature[0]),
self.getArgs(signature[0], signature[1]),
static=member.isStatic(),
# Mark our getters, which are attrs that
@@ -4603,274 +4610,16 @@ class CGNativeMember(ClassMethod):
breakAfterSelf=breakAfterSelf,
visibility=visibility)
- def getReturnType(self, type, isMember):
- return self.getRetvalInfo(type, isMember)[0]
-
- def getRetvalInfo(self, type, isMember):
- """
- Returns a tuple:
-
- The first element is the type declaration for the retval
-
- The second element is a template for actually returning a value stored in
- "${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.
- """
- if type.isVoid():
- typeDecl, template = "", ""
- elif type.isPrimitive() and type.tag() in builtinNames:
- result = CGGeneric(builtinNames[type.tag()])
- if type.nullable():
- raise TypeError("Nullable primitives are not supported here.")
-
- typeDecl, template = result.define(), "return Ok(${declName});"
- elif type.isDOMString():
- if isMember:
- # No need for a third element in the isMember case
- typeDecl, template = "nsString", None
- # Outparam
- else:
- typeDecl, template = "void", "retval = ${declName};"
- elif type.isByteString():
- if isMember:
- # No need for a third element in the isMember case
- typeDecl, template = "nsCString", None
- # Outparam
- typeDecl, template = "void", "retval = ${declName};"
- elif type.isEnum():
- enumName = type.unroll().inner.identifier.name
- if type.nullable():
- enumName = CGTemplatedType("Nullable",
- CGGeneric(enumName)).define()
- typeDecl, template = enumName, "return ${declName};"
- elif type.isGeckoInterface():
- iface = type.unroll().inner;
- nativeType = self.descriptorProvider.getDescriptor(
- iface.identifier.name).nativeType
- # Now trim off unnecessary namespaces
- nativeType = nativeType.split("::")
- if nativeType[0] == "mozilla":
- nativeType.pop(0)
- if nativeType[0] == "dom":
- nativeType.pop(0)
- result = CGWrapper(CGGeneric("::".join(nativeType)), post="*")
- # Since we always force an owning type for callback return values,
- # our ${declName} is an OwningNonNull or nsRefPtr. So we can just
- # .forget() to get our already_AddRefed.
- typeDecl, template = result.define(), "return ${declName}.forget();"
- elif type.isCallback():
- typeDecl, template = \
- ("already_AddRefed<%s>" % type.unroll().identifier.name,
- "return ${declName}.forget();")
- elif type.isAny():
- typeDecl, template = "JSVal", "return Ok(${declName});"
- elif type.isObject():
- typeDecl, template = "JSObject*", "return ${declName};"
- elif type.isSpiderMonkeyInterface():
- if type.nullable():
- returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();"
- else:
- returnCode = "return ${declName}.Obj();"
- typeDecl, template = "JSObject*", returnCode
- elif type.isSequence():
- # If we want to handle sequence-of-sequences return values, we're
- # going to need to fix example codegen to not produce nsTArray<void>
- # for the relevant argument...
- assert not isMember
- # Outparam.
- if type.nullable():
- returnCode = ("if (${declName}.IsNull()) {\n"
- " retval.SetNull();\n"
- "} else {\n"
- " retval.SetValue().SwapElements(${declName}.Value());\n"
- "}")
- else:
- returnCode = "retval.SwapElements(${declName});"
- typeDecl, template = "void", returnCode
- elif type.isDate():
- result = CGGeneric("Date")
- if type.nullable():
- result = CGTemplatedType("Nullable", result)
- typeDecl, template = result.define(), "return ${declName};"
- else:
- raise TypeError("Don't know how to declare return value for %s" % type)
-
- if not 'infallible' in self.extendedAttrs:
- if typeDecl:
- typeDecl = "Fallible<%s>" % typeDecl
- else:
- typeDecl = "ErrorResult"
- if not template:
- template = "return Ok(());"
- return typeDecl, template
+ def getReturnType(self, type):
+ infallible = 'infallible' in self.extendedAttrs
+ typeDecl = return_type(self.descriptorProvider, type, infallible)
+ return typeDecl
def getArgs(self, returnType, argList):
- args = [self.getArg(arg) for arg in argList]
- # Now the outparams
- if returnType.isDOMString():
- args.append(Argument("nsString&", "retval"))
- if returnType.isByteString():
- args.append(Argument("nsCString&", "retval"))
- elif returnType.isSequence():
- nullable = returnType.nullable()
- if nullable:
- returnType = returnType.inner
- # And now the actual underlying type
- elementDecl = self.getReturnType(returnType.inner, True)
- type = CGTemplatedType("nsTArray", CGGeneric(elementDecl))
- if nullable:
- type = CGTemplatedType("Nullable", type)
- args.append(Argument("%s&" % type.define(), "retval"))
- # The legacycaller thisval
- if self.member.isMethod() and self.member.isLegacycaller():
- # If it has an identifier, we can't deal with it yet
- assert self.member.isIdentifierLess()
- args.insert(0, Argument("JS::Value", "aThisVal"))
- # And jscontext bits.
- if needCx(returnType, argList, self.passJSBitsAsNeeded):
- args.insert(0, Argument("JSContext*", "cx"))
- # And if we're static, a global
- if self.member.isStatic():
- args.insert(0, Argument("const GlobalObject&", "global"))
- return args
-
- def doGetArgType(self, type, optional, isMember):
- """
- The main work of getArgType. Returns a string type decl, whether this
- is a const ref, as well as whether the type should be wrapped in
- Nullable as needed.
-
- isMember can be false or one of the strings "Sequence" or "Variadic"
- """
- if type.isArray():
- raise TypeError("Can't handle array arguments yet")
-
- if type.isSequence():
- nullable = type.nullable()
- if nullable:
- type = type.inner
- elementType = type.inner
- argType = self.getArgType(elementType, False, "Sequence")[0]
- decl = CGTemplatedType("Sequence", argType)
- return decl.define(), True, True
-
- if type.isUnion():
- return union_native_type(type), False, True
-
- if type.isGeckoInterface() and not type.isCallbackInterface():
- iface = type.unroll().inner
- argIsPointer = type.nullable()
- forceOwningType = iface.isCallback() or isMember
- if argIsPointer:
- if (optional or isMember) and forceOwningType:
- typeDecl = "nsRefPtr<%s>"
- else:
- typeDecl = "*%s"
- else:
- if optional or isMember:
- if forceOwningType:
- typeDecl = "OwningNonNull<%s>"
- else:
- typeDecl = "NonNull<%s>"
- else:
- typeDecl = "%s"
- descriptor = self.descriptorProvider.getDescriptor(iface.identifier.name)
- return (typeDecl % descriptor.argumentType,
- False, False)
-
- if type.isSpiderMonkeyInterface():
- if self.jsObjectsArePtr:
- return "JSObject*", False, False
-
- return type.name, True, True
-
- if type.isDOMString():
- declType = "DOMString"
- return declType, True, False
-
- if type.isByteString():
- declType = "nsCString"
- return declType, True, False
-
- if type.isEnum():
- return type.unroll().inner.identifier.name, False, True
-
- if type.isCallback() or type.isCallbackInterface():
- forceOwningType = optional or isMember
- if type.nullable():
- if forceOwningType:
- declType = "nsRefPtr<%s>"
- else:
- declType = "%s*"
- else:
- if forceOwningType:
- declType = "OwningNonNull<%s>"
- else:
- declType = "%s&"
- if type.isCallback():
- name = type.unroll().identifier.name
- else:
- name = type.unroll().inner.identifier.name
- return declType % name, False, False
-
- if type.isAny():
- # Don't do the rooting stuff for variadics for now
- if isMember:
- declType = "JS::Value"
- else:
- declType = "JSVal"
- return declType, False, False
-
- if type.isObject():
- if isMember:
- declType = "JSObject*"
- else:
- declType = "JS::Handle<JSObject*>"
- return declType, False, False
-
- if type.isDictionary():
- typeName = CGDictionary.makeDictionaryName(type.inner)
- return typeName, True, True
-
- if type.isDate():
- return "Date", False, True
-
- assert type.isPrimitive()
-
- return builtinNames[type.tag()], False, True
-
- def getArgType(self, type, optional, isMember):
- """
- Get the type of an argument declaration. Returns the type CGThing, and
- whether this should be a const ref.
-
- isMember can be False, "Sequence", or "Variadic"
- """
- (decl, ref, handleNullable) = self.doGetArgType(type, optional,
- isMember)
- decl = CGGeneric(decl)
- if handleNullable and type.nullable():
- decl = CGTemplatedType("Nullable", decl)
- if isMember == "Variadic":
- arrayType = "Sequence" if self.variadicIsSequence else "nsTArray"
- decl = CGTemplatedType(arrayType, decl)
- elif optional:
- # Note: All variadic args claim to be optional, but we can just use
- # empty arrays to represent them not being present.
- decl = CGTemplatedType("Option", decl)
- return decl
-
- def getArg(self, arg):
- """
- Get the full argument declaration for an argument
- """
- decl = self.getArgType(arg.type,
- arg.optional and not arg.defaultValue,
- "Variadic" if arg.variadic else False)
-
- return Argument(decl.define(), arg.identifier.name)
+ return [Argument(arg[1], arg[0]) for arg in method_arguments(self.descriptorProvider,
+ returnType,
+ argList,
+ self.passJSBitsAsNeeded)]
class CGCallback(CGClass):
def __init__(self, idlObject, descriptorProvider, baseName, methods,
@@ -5052,8 +4801,8 @@ class CallbackMember(CGNativeMember):
lastArg = args[self.argCount-1]
if lastArg.variadic:
self.argCountStr = (
- "(%d - 1) + %s.Length()" % (self.argCount,
- lastArg.identifier.name))
+ "(%d - 1) + %s.len()" % (self.argCount,
+ lastArg.identifier.name))
else:
self.argCountStr = "%d" % self.argCount
self.needThisHandling = needThisHandling
@@ -5111,7 +4860,6 @@ class CallbackMember(CGNativeMember):
def getResultConversion(self):
replacements = {
"val": "rval",
- "declName": "rvalDecl",
}
template, _, declType, needsRooting = getJSToNativeConversionTemplate(
@@ -5125,10 +4873,12 @@ class CallbackMember(CGNativeMember):
convertType = instantiateJSToNativeConversionTemplate(
template, replacements, declType, "rvalDecl", needsRooting)
- assignRetval = string.Template(
- self.getRetvalInfo(self.retvalType,
- False)[1]).substitute(replacements)
- return convertType.define() + "\n" + assignRetval + "\n"
+ if self.retvalType is None or self.retvalType.isVoid():
+ retval = "()"
+ else:
+ retval = "rvalDecl"
+
+ return "%s\nOk(%s)\n" % (convertType.define(), retval)
def getArgConversions(self):
# Just reget the arglist from self.originalSig, because our superclasses
@@ -5139,12 +4889,7 @@ class CallbackMember(CGNativeMember):
# Do them back to front, so our argc modifications will work
# correctly, because we examine trailing arguments first.
argConversions.reverse();
- # Wrap each one in a scope so that any locals it has don't leak out, and
- # also so that we can just "break;" for our successCode.
- argConversions = [CGWrapper(CGIndenter(CGGeneric(c)),
- pre="loop {\n",
- post="\nbreak;}\n")
- for c in argConversions]
+ argConversions = [CGGeneric(c) for c in argConversions]
if self.argCount > 0:
argConversions.insert(0, self.getArgcDecl())
# And slap them together.
@@ -5163,13 +4908,13 @@ class CallbackMember(CGNativeMember):
conversion = wrapForType("argv[%s]" % jsvalIndex,
result=argval,
- successCode="continue;" if arg.variadic else "break;")
+ successCode="")
if arg.variadic:
conversion = string.Template(
- "for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {\n" +
+ "for idx in range(0, ${arg}.len()) {\n" +
CGIndenter(CGGeneric(conversion)).define() + "\n"
"}\n"
- "break;").substitute({ "arg": arg.identifier.name })
+ ).substitute({ "arg": arg.identifier.name })
elif arg.optional and not arg.defaultValue:
conversion = (
CGIfWrapper(CGGeneric(conversion),
@@ -5220,7 +4965,7 @@ class CallbackMember(CGNativeMember):
})
def getArgcDecl(self):
- return CGGeneric("let mut argc = %su32;" % self.argCountStr);
+ return CGGeneric("let mut argc = %s as u32;" % self.argCountStr);
@staticmethod
def ensureASCIIName(idlObject):