aboutsummaryrefslogtreecommitdiffstats
path: root/src/servo/dom/bindings/codegen/CodegenRust.py
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2013-01-16 15:04:36 +0100
committerJosh Matthews <josh@joshmatthews.net>2013-03-13 11:40:16 -0400
commitebd1ce8055fcca488ca91fff768afdbf34d24a5f (patch)
tree9b17b8d9b39ba75a92ee570bedfe8b39c485ad5f /src/servo/dom/bindings/codegen/CodegenRust.py
parent30676402f5de81f869fcbeff1d639f74c5ebcc9c (diff)
downloadservo-ebd1ce8055fcca488ca91fff768afdbf34d24a5f.tar.gz
servo-ebd1ce8055fcca488ca91fff768afdbf34d24a5f.zip
Initial dump of codegen work. Requires manual running of various python scripts to build servo.
Diffstat (limited to 'src/servo/dom/bindings/codegen/CodegenRust.py')
-rw-r--r--src/servo/dom/bindings/codegen/CodegenRust.py1291
1 files changed, 1291 insertions, 0 deletions
diff --git a/src/servo/dom/bindings/codegen/CodegenRust.py b/src/servo/dom/bindings/codegen/CodegenRust.py
new file mode 100644
index 00000000000..44d01e4ed9a
--- /dev/null
+++ b/src/servo/dom/bindings/codegen/CodegenRust.py
@@ -0,0 +1,1291 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Common codegen classes.
+
+import os
+import string
+import operator
+
+from WebIDL import *
+from Configuration import NoSuchDescriptorError
+
+AUTOGENERATED_WARNING_COMMENT = \
+ "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
+ADDPROPERTY_HOOK_NAME = '_addProperty'
+FINALIZE_HOOK_NAME = '_finalize'
+TRACE_HOOK_NAME = '_trace'
+CONSTRUCT_HOOK_NAME = '_constructor'
+HASINSTANCE_HOOK_NAME = '_hasInstance'
+
+def replaceFileIfChanged(filename, newContents):
+ """
+ Read a copy of the old file, so that we don't touch it if it hasn't changed.
+ Returns True if the file was updated, false otherwise.
+ """
+ oldFileContents = ""
+ try:
+ oldFile = open(filename, 'rb')
+ oldFileContents = ''.join(oldFile.readlines())
+ oldFile.close()
+ except:
+ pass
+
+ if newContents == oldFileContents:
+ return False
+
+ f = open(filename, 'wb')
+ f.write(newContents)
+ f.close()
+
+def toStringBool(arg):
+ return str(not not arg).lower()
+
+def toBindingNamespace(arg):
+ return re.sub("((_workers)?$)", "Binding\\1", arg);
+
+def stripTrailingWhitespace(text):
+ tail = '\n' if text.endswith('\n') else ''
+ lines = text.splitlines()
+ for i in range(len(lines)):
+ lines[i] = lines[i].rstrip()
+ return '\n'.join(lines) + tail
+
+def MakeNativeName(name):
+ return name[0].upper() + name[1:]
+
+builtinNames = {
+ IDLType.Tags.bool: 'bool',
+ IDLType.Tags.int8: 'i8',
+ IDLType.Tags.int16: 'i16',
+ IDLType.Tags.int32: 'i32',
+ IDLType.Tags.int64: 'i64',
+ IDLType.Tags.uint8: 'u8',
+ IDLType.Tags.uint16: 'u16',
+ IDLType.Tags.uint32: 'u32',
+ IDLType.Tags.uint64: 'u64',
+ IDLType.Tags.float: 'f32',
+ IDLType.Tags.double: 'f64'
+}
+
+class CastableObjectUnwrapper():
+ """
+ A class for unwrapping an object named by the "source" argument
+ based on the passed-in descriptor and storing it in a variable
+ called by the name in the "target" argument.
+
+ codeOnFailure is the code to run if unwrapping fails.
+ """
+ def __init__(self, descriptor, source, target, codeOnFailure):
+ assert descriptor.castable
+
+ self.substitution = { "type" : descriptor.nativeType,
+ "protoID" : "prototypes::id::" + descriptor.name,
+ "source" : source,
+ "target" : target,
+ "codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure), 4).define() }
+ if descriptor.hasXPConnectImpls:
+ # We don't use xpc_qsUnwrapThis because it will always throw on
+ # unwrap failure, whereas we want to control whether we throw or
+ # not.
+ self.substitution["codeOnFailure"] = CGIndenter(CGGeneric(string.Template(
+ "${type} *objPtr;\n"
+ "xpc_qsSelfRef objRef;\n"
+ "JS::Value val = JS::ObjectValue(*${source});\n"
+ "nsresult rv = xpc_qsUnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n"
+ "if (NS_FAILED(rv)) {\n"
+ "${codeOnFailure}\n"
+ "}\n"
+ "// We should be castable!\n"
+ "MOZ_ASSERT(!objRef.ptr);\n"
+ "// We should have an object, too!\n"
+ "MOZ_ASSERT(objPtr);\n"
+ "${target} = objPtr;").substitute(self.substitution)), 4).define()
+
+ def __str__(self):
+ return string.Template(
+"""${target} = unwrap<${type}>(${source});
+""").substitute(self.substitution)
+#"""{
+# nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target});
+# if (NS_FAILED(rv)) {
+#${codeOnFailure}
+# }
+#}""").substitute(self.substitution)
+
+class FakeCastableDescriptor():
+ def __init__(self, descriptor):
+ self.castable = True
+ self.workers = descriptor.workers
+ self.nativeType = descriptor.nativeType
+ self.name = descriptor.name
+ self.hasXPConnectImpls = descriptor.hasXPConnectImpls
+
+def getWrapTemplateForType(type, descriptorProvider, result, successCode,
+ isCreator):
+ """
+ Reflect a C++ value stored in "result", of IDL type "type" into JS. The
+ "successCode" is the code to run once we have successfully done the
+ conversion. The resulting string should be used with string.Template, it
+ needs the following keys when substituting: jsvalPtr/jsvalRef/obj.
+
+ Returns (templateString, infallibility of conversion template)
+ """
+ haveSuccessCode = successCode is not None
+ if not haveSuccessCode:
+ successCode = "return true;"
+
+ def setValue(value, callWrapValue=False):
+ """
+ Returns the code to set the jsval to value. If "callWrapValue" is true
+ JS_WrapValue will be called on the jsval.
+ """
+ if not callWrapValue:
+ tail = successCode
+ elif haveSuccessCode:
+ tail = ("if (!JS_WrapValue(cx, ${jsvalPtr})) {\n" +
+ " return false;\n" +
+ "}\n" +
+ successCode)
+ else:
+ tail = "return JS_WrapValue(cx, ${jsvalPtr});"
+ return ("${jsvalRef} = %s;\n" +
+ tail) % (value)
+
+ def wrapAndSetPtr(wrapCall, failureCode=None):
+ """
+ Returns the code to set the jsval by calling "wrapCall". "failureCode"
+ is the code to run if calling "wrapCall" fails
+ """
+ if failureCode is None:
+ if not haveSuccessCode:
+ return "return " + wrapCall + ";"
+ failureCode = "return false;"
+ str = ("if (!%s) {\n" +
+ CGIndenter(CGGeneric(failureCode)).define() + "\n" +
+ "}\n" +
+ successCode) % (wrapCall)
+ return str
+
+ if type is None or type.isVoid():
+ return (setValue("JSVAL_VOID"), True)
+
+ if type.isArray():
+ raise TypeError("Can't handle array return values yet")
+
+ if type.isSequence():
+ if type.nullable():
+ # Nullable sequences are Nullable< nsTArray<T> >
+ (recTemplate, recInfall) = getWrapTemplateForType(type.inner, descriptorProvider,
+ "%s.Value()" % result, successCode,
+ isCreator)
+ return ("""
+if (%s.IsNull()) {
+%s
+}
+%s""" % (result, CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define(), recTemplate), recInfall)
+
+ # Now do non-nullable sequences. We use setting the element
+ # in the array as our succcess code because when we succeed in
+ # wrapping that's what we should do.
+ innerTemplate = wrapForType(
+ type.inner, descriptorProvider,
+ {
+ 'result' : "%s[i]" % result,
+ 'successCode': ("if (!JS_DefineElement(cx, returnArray, i, tmp,\n"
+ " NULL, NULL, JSPROP_ENUMERATE)) {\n"
+ " return false;\n"
+ "}"),
+ 'jsvalRef': "tmp",
+ 'jsvalPtr': "&tmp",
+ 'isCreator': isCreator
+ }
+ )
+ innerTemplate = CGIndenter(CGGeneric(innerTemplate)).define()
+ return (("""
+uint32_t length = %s.Length();
+JSObject *returnArray = JS_NewArrayObject(cx, length, NULL);
+if (!returnArray) {
+ return false;
+}
+jsval tmp;
+for (uint32_t i = 0; i < length; ++i) {
+%s
+}\n""" % (result, innerTemplate)) + setValue("JS::ObjectValue(*returnArray)"), False)
+
+ if type.isGeckoInterface():
+ descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
+ if type.nullable():
+ wrappingCode = ("if (!%s) {\n" % (result) +
+ CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
+ "}\n")
+ else:
+ wrappingCode = ""
+ if (not descriptor.interface.isExternal() and
+ not descriptor.interface.isCallback()):
+ if descriptor.wrapperCache:
+ wrapMethod = "WrapNewBindingObject"
+ else:
+ if not isCreator:
+ raise MethodNotCreatorError(descriptor.interface.identifier.name)
+ wrapMethod = "WrapNewBindingNonWrapperCachedObject"
+ wrap = "%s(cx, ${obj}, %s, ${jsvalPtr})" % (wrapMethod, result)
+ # We don't support prefable stuff in workers.
+ assert(not descriptor.prefable or not descriptor.workers)
+ if not descriptor.prefable:
+ # Non-prefable bindings can only fail to wrap as a new-binding object
+ # if they already threw an exception. Same thing for
+ # non-prefable bindings.
+ failed = ("MOZ_ASSERT(JS_IsExceptionPending(cx));\n" +
+ "return false;")
+ else:
+ if descriptor.notflattened:
+ raise TypeError("%s is prefable but not flattened; "
+ "fallback won't work correctly" %
+ descriptor.interface.identifier.name)
+ # Try old-style wrapping for bindings which might be preffed off.
+ failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalPtr})" % result)
+ wrappingCode += wrapAndSetPtr(wrap, failed)
+ else:
+ if descriptor.notflattened:
+ getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
+ else:
+ getIID = ""
+ wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID)
+ wrappingCode += wrapAndSetPtr(wrap)
+ return (wrappingCode, False)
+
+ if type.isString():
+ if type.nullable():
+ return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalPtr})" % result), False)
+ else:
+ return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalPtr})" % result), False)
+
+ if type.isEnum():
+ if type.nullable():
+ raise TypeError("We don't support nullable enumerated return types "
+ "yet")
+ return ("""MOZ_ASSERT(uint32_t(%(result)s) < ArrayLength(%(strings)s));
+JSString* %(resultStr)s = JS_NewStringCopyN(cx, %(strings)s[uint32_t(%(result)s)].value, %(strings)s[uint32_t(%(result)s)].length);
+if (!%(resultStr)s) {
+ return false;
+}
+""" % { "result" : result,
+ "resultStr" : result + "_str",
+ "strings" : type.inner.identifier.name + "Values::strings" } +
+ setValue("JS::StringValue(%s_str)" % result), False)
+
+ if type.isCallback():
+ assert not type.isInterface()
+ # XXXbz we're going to assume that callback types are always
+ # nullable and always have [TreatNonCallableAsNull] for now.
+ # See comments in WrapNewBindingObject explaining why we need
+ # to wrap here.
+ # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
+ return (setValue("JS::ObjectOrNullValue(%s)" % result, True), False)
+
+ if type.tag() == IDLType.Tags.any:
+ # See comments in WrapNewBindingObject explaining why we need
+ # to wrap here.
+ # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
+ return (setValue(result, True), False)
+
+ if type.isObject() or type.isSpiderMonkeyInterface():
+ # See comments in WrapNewBindingObject explaining why we need
+ # to wrap here.
+ if type.nullable():
+ toValue = "JS::ObjectOrNullValue(%s)"
+ else:
+ toValue = "JS::ObjectValue(*%s)"
+ # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
+ return (setValue(toValue % result, True), False)
+
+ if not type.isPrimitive():
+ raise TypeError("Need to learn to wrap %s" % type)
+
+ if type.nullable():
+ (recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider,
+ "%s.Value()" % result, successCode,
+ isCreator)
+ return ("if (%s.IsNull()) {\n" % result +
+ CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
+ "}\n" + recTemplate, recInfal)
+
+ tag = type.tag()
+
+ if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
+ IDLType.Tags.uint16, IDLType.Tags.int32]:
+ return (setValue("INT_TO_JSVAL(int32_t(%s))" % result), True)
+
+ elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, IDLType.Tags.float,
+ IDLType.Tags.double]:
+ # XXXbz will cast to double do the "even significand" thing that webidl
+ # calls for for 64-bit ints? Do we care?
+ return (setValue("JS_NumberValue(%s as f64)" % result), True)
+
+ elif tag == IDLType.Tags.uint32:
+ return (setValue("UINT_TO_JSVAL(%s)" % result), True)
+
+ elif tag == IDLType.Tags.bool:
+ return (setValue("BOOLEAN_TO_JSVAL(%s)" % result), True)
+
+ else:
+ raise TypeError("Need to learn to wrap primitive: %s" % type)
+
+def wrapForType(type, descriptorProvider, templateValues):
+ """
+ Reflect a C++ value of IDL type "type" into JS. TemplateValues is a dict
+ that should contain:
+
+ * 'jsvalRef': a C++ reference to the jsval in which to store the result of
+ the conversion
+ * 'jsvalPtr': a C++ pointer to the jsval in which to store the result of
+ the conversion
+ * 'obj' (optional): the name of the variable that contains the JSObject to
+ use as a scope when wrapping, if not supplied 'obj'
+ will be used as the name
+ * 'result' (optional): the name of the variable in which the C++ value is
+ stored, if not supplied 'result' will be used as
+ the name
+ * 'successCode' (optional): the code to run once we have successfully done
+ the conversion, if not supplied 'return true;'
+ will be used as the code
+ * 'isCreator' (optional): If true, we're wrapping for the return value of
+ a [Creator] method. Assumed false if not set.
+ """
+ wrap = getWrapTemplateForType(type, descriptorProvider,
+ templateValues.get('result', 'result'),
+ templateValues.get('successCode', None),
+ templateValues.get('isCreator', False))[0]
+
+ defaultValues = {'obj': 'obj'}
+ return string.Template(wrap).substitute(defaultValues, **templateValues)
+
+def typeNeedsCx(type, retVal=False):
+ if type is None:
+ return False
+ if type.nullable():
+ type = type.inner
+ if type.isSequence() or type.isArray():
+ type = type.inner
+ if type.isUnion():
+ return any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes)
+ if retVal and type.isSpiderMonkeyInterface():
+ return True
+ return type.isCallback() or type.isAny() or type.isObject()
+
+def memberIsCreator(member):
+ return member.getExtendedAttribute("Creator") is not None
+
+# Returns a tuple consisting of a CGThing containing the type of the return
+# value, or None if there is no need for a return value, and a boolean signaling
+# whether the return value is passed in an out parameter.
+def getRetvalDeclarationForType(returnType, descriptorProvider,
+ resultAlreadyAddRefed):
+ if returnType is None or returnType.isVoid():
+ # Nothing to declare
+ return None, False
+ if returnType.isPrimitive() and returnType.tag() in builtinNames:
+ result = CGGeneric(builtinNames[returnType.tag()])
+ if returnType.nullable():
+ result = CGWrapper(result, pre="Nullable<", post=">")
+ return result, False
+ if returnType.isString():
+ return CGGeneric("nsString"), True
+ if returnType.isEnum():
+ if returnType.nullable():
+ raise TypeError("We don't support nullable enum return values")
+ return CGGeneric(returnType.inner.identifier.name), False
+ if returnType.isGeckoInterface():
+ result = CGGeneric(descriptorProvider.getDescriptor(
+ returnType.unroll().inner.identifier.name).nativeType)
+ if resultAlreadyAddRefed:
+ result = CGWrapper(result, pre="nsRefPtr<", post=">")
+ else:
+ result = CGWrapper(result, post="*")
+ return result, False
+ if returnType.isCallback():
+ # XXXbz we're going to assume that callback types are always
+ # nullable for now.
+ return CGGeneric("*JSObject"), False
+ if returnType.isAny():
+ return CGGeneric("jsval"), False
+ if returnType.isObject() or returnType.isSpiderMonkeyInterface():
+ return CGGeneric("*JSObject"), False
+ if returnType.isSequence():
+ nullable = returnType.nullable()
+ if nullable:
+ returnType = returnType.inner
+ # If our result is already addrefed, use the right type in the
+ # sequence argument here.
+ (result, _) = getRetvalDeclarationForType(returnType.inner,
+ descriptorProvider,
+ resultAlreadyAddRefed)
+ result = CGWrapper(result, pre="nsTArray< ", post=" >")
+ if nullable:
+ result = CGWrapper(result, pre="Nullable< ", post=" >")
+ return result, True
+ raise TypeError("Don't know how to declare return value for %s" %
+ returnType)
+
+class PropertyArrays():
+ def __init__(self, descriptor):
+ #self.staticMethods = MethodDefiner(descriptor, "StaticMethods", True)
+ #self.methods = MethodDefiner(descriptor, "Methods", False)
+ #self.attrs = AttrDefiner(descriptor, "Attributes")
+ #self.consts = ConstDefiner(descriptor, "Constants")
+ pass
+
+ @staticmethod
+ def arrayNames():
+ return [ "staticMethods", "methods", "attrs", "consts" ]
+
+ @staticmethod
+ def xrayRelevantArrayNames():
+ return [ "methods", "attrs", "consts" ]
+
+ def hasChromeOnly(self):
+ return reduce(lambda b, a: b or getattr(self, a).hasChromeOnly(),
+ self.arrayNames(), False)
+ def variableNames(self, chrome):
+ names = {}
+ for array in self.arrayNames():
+ names[array] = getattr(self, array).variableName(chrome)
+ return names
+ def __str__(self):
+ define = ""
+ for array in self.arrayNames():
+ define += str(getattr(self, array))
+ return define
+
+class CGThing():
+ """
+ Abstract base class for things that spit out code.
+ """
+ def __init__(self):
+ pass # Nothing for now
+ def declare(self):
+ """Produce code for a header file."""
+ assert(False) # Override me!
+ def define(self):
+ """Produce code for a cpp file."""
+ assert(False) # Override me!
+
+# We'll want to insert the indent at the beginnings of lines, but we
+# don't want to indent empty lines. So only indent lines that have a
+# non-newline character on them.
+lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
+class CGIndenter(CGThing):
+ """
+ A class that takes another CGThing and generates code that indents that
+ CGThing by some number of spaces. The default indent is two spaces.
+ """
+ def __init__(self, child, indentLevel=2, declareOnly=False):
+ CGThing.__init__(self)
+ self.child = child
+ self.indent = " " * indentLevel
+ self.declareOnly = declareOnly
+ def declare(self):
+ decl = self.child.declare()
+ if decl is not "":
+ return re.sub(lineStartDetector, self.indent, decl)
+ else:
+ return ""
+ def define(self):
+ defn = self.child.define()
+ if defn is not "" and not self.declareOnly:
+ return re.sub(lineStartDetector, self.indent, defn)
+ else:
+ return defn
+
+class CGWrapper(CGThing):
+ """
+ Generic CGThing that wraps other CGThings with pre and post text.
+ """
+ def __init__(self, child, pre="", post="", declarePre=None,
+ declarePost=None, definePre=None, definePost=None,
+ declareOnly=False, defineOnly=False, reindent=False):
+ CGThing.__init__(self)
+ self.child = child
+ self.declarePre = declarePre or pre
+ self.declarePost = declarePost or post
+ self.definePre = definePre or pre
+ self.definePost = definePost or post
+ self.declareOnly = declareOnly
+ self.defineOnly = defineOnly
+ self.reindent = reindent
+ def declare(self):
+ if self.defineOnly:
+ return ''
+ decl = self.child.declare()
+ if self.reindent:
+ # We don't use lineStartDetector because we don't want to
+ # insert whitespace at the beginning of our _first_ line.
+ decl = stripTrailingWhitespace(
+ decl.replace("\n", "\n" + (" " * len(self.declarePre))))
+ return self.declarePre + decl + self.declarePost
+ def define(self):
+ if self.declareOnly:
+ return ''
+ defn = self.child.define()
+ if self.reindent:
+ # We don't use lineStartDetector because we don't want to
+ # insert whitespace at the beginning of our _first_ line.
+ defn = stripTrailingWhitespace(
+ defn.replace("\n", "\n" + (" " * len(self.definePre))))
+ return self.definePre + defn + self.definePost
+
+class CGImports(CGWrapper):
+ """
+ Generates the appropriate import/use statements.
+ """
+ def __init__(self, descriptors, dictionaries, declareImports, defineImports, child):
+ """
+ Builds a set of imports to cover |descriptors|.
+
+ Also includes the files in |declareIncludes| in the header
+ file and the files in |defineIncludes| in the .cpp.
+ """
+
+ # TODO imports to cover descriptors, etc.
+
+ def _useString(imports):
+ return ''.join(['use %s;\n' % i for i in imports]) + '\n'
+ CGWrapper.__init__(self, child,
+ definePre=_useString(sorted(defineImports)))
+
+class CGNamespace(CGWrapper):
+ def __init__(self, namespace, child, declareOnly=False):
+ pre = "mod %s {\n" % namespace
+ post = "} // mod %s\n" % namespace
+ CGWrapper.__init__(self, child, pre=pre, post=post,
+ declareOnly=declareOnly)
+ @staticmethod
+ def build(namespaces, child, declareOnly=False):
+ """
+ Static helper method to build multiple wrapped namespaces.
+ """
+ if not namespaces:
+ return CGWrapper(child, declareOnly=declareOnly)
+ inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly)
+ return CGNamespace(namespaces[0], inner, declareOnly=declareOnly)
+
+class CGList(CGThing):
+ """
+ Generate code for a list of GCThings. Just concatenates them together, with
+ an optional joiner string. "\n" is a common joiner.
+ """
+ def __init__(self, children, joiner=""):
+ CGThing.__init__(self)
+ self.children = children
+ self.joiner = joiner
+ def append(self, child):
+ self.children.append(child)
+ def prepend(self, child):
+ self.children.insert(0, child)
+ def join(self, generator):
+ return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator)))
+ def declare(self):
+ return self.join(child.declare() for child in self.children if child is not None)
+ def define(self):
+ return self.join(child.define() for child in self.children if child is not None)
+
+class CGGeneric(CGThing):
+ """
+ A class that spits out a fixed string into the codegen. Can spit out a
+ separate string for the declaration too.
+ """
+ def __init__(self, define="", declare=""):
+ self.declareText = declare
+ self.defineText = define
+ def declare(self):
+ return self.declareText
+ def define(self):
+ return self.defineText
+
+class Argument():
+ """
+ A class for outputting the type and name of an argument
+ """
+ def __init__(self, argType, name):
+ self.argType = argType
+ self.name = name
+ def __str__(self):
+ return self.name + ': ' + self.argType
+
+class CGAbstractMethod(CGThing):
+ """
+ An abstract class for generating code for a method. Subclasses
+ should override definition_body to create the actual code.
+
+ descriptor is the descriptor for the interface the method is associated with
+
+ name is the name of the method as a string
+
+ returnType is the IDLType of the return value
+
+ args is a list of Argument objects
+
+ inline should be True to generate an inline method, whose body is
+ part of the declaration.
+
+ alwaysInline should be True to generate an inline method annotated with
+ MOZ_ALWAYS_INLINE.
+
+ static should be True to generate a static method, which only has
+ a definition.
+
+ If templateArgs is not None it should be a list of strings containing
+ template arguments, and the function will be templatized using those
+ arguments.
+ """
+ def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, extern=False, templateArgs=None):
+ CGThing.__init__(self)
+ self.descriptor = descriptor
+ self.name = name
+ self.returnType = returnType
+ self.args = args
+ self.inline = inline
+ self.alwaysInline = alwaysInline
+ self.static = static
+ self.extern = extern
+ self.templateArgs = templateArgs
+ def _argstring(self):
+ return ', '.join([str(a) for a in self.args])
+ def _template(self):
+ if self.templateArgs is None:
+ return ''
+ return '<%s>\n' % ', '.join(self.templateArgs)
+ def _decorators(self):
+ decorators = []
+ if self.alwaysInline:
+ decorators.append('#[inline(always)]')
+ elif self.inline:
+ #decorators.append('inline')
+ pass
+ if self.extern:
+ decorators.append('extern')
+ if self.static:
+ #decorators.append('static')
+ pass
+ if not decorators:
+ return ''
+ #maybeNewline = " " if self.inline else "\n"
+ maybeNewline = " "
+ return ' '.join(decorators) + maybeNewline
+ def _returnType(self):
+ return (" -> %s" % self.returnType) if self.returnType != "void" else ""
+ def declare(self):
+ if self.inline:
+ return self._define()
+ return "%sfn %s%s(%s)%s;\n" % (self._decorators(), self.name, self._template(),
+ self.name, self._argstring(), self._returnType())
+ def _define(self):
+ return self.definition_prologue() + "\n" + self.definition_body() + self.definition_epilogue()
+ def define(self):
+ return "" if self.inline else self._define()
+ def definition_prologue(self):
+ return "%sfn %s%s(%s)%s unsafe {" % (self._decorators(), self.name, self._template(),
+ self._argstring(), self._returnType())
+ def definition_epilogue(self):
+ return "\n}\n"
+ def definition_body(self):
+ assert(False) # Override me!
+
+class CGAbstractExternMethod(CGAbstractMethod):
+ """
+ Abstract base class for codegen of implementation-only (no
+ declaration) static methods.
+ """
+ def __init__(self, descriptor, name, returnType, args):
+ CGAbstractMethod.__init__(self, descriptor, name, returnType, args,
+ inline=False, extern=True)
+ def declare(self):
+ # We only have implementation
+ return ""
+
+class CGCallGenerator(CGThing):
+ """
+ A class to generate an actual call to a C++ object. Assumes that the C++
+ object is stored in a variable whose name is given by the |object| argument.
+
+ errorReport should be a CGThing for an error report or None if no
+ error reporting is needed.
+ """
+ def __init__(self, errorReport, arguments, argsPre, returnType,
+ extendedAttributes, descriptorProvider, nativeMethodName,
+ static, object="self", declareResult=True):
+ CGThing.__init__(self)
+
+ assert errorReport is None or isinstance(errorReport, CGThing)
+
+ isFallible = errorReport is not None
+
+ #resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
+ # extendedAttributes)
+ resultAlreadyAddRefed = True
+ (result, resultOutParam) = getRetvalDeclarationForType(returnType,
+ descriptorProvider,
+ resultAlreadyAddRefed)
+
+ args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
+ for (a, name) in arguments:
+ # This is a workaround for a bug in Apple's clang.
+ if a.type.isObject() and not a.type.nullable() and not a.optional:
+ name = "(JSObject&)" + name
+ args.append(CGGeneric(name))
+
+ # Return values that go in outparams go here
+ if resultOutParam:
+ args.append(CGGeneric("result"))
+ if isFallible:
+ args.append(CGGeneric("rv"))
+
+ needsCx = (typeNeedsCx(returnType, True) or
+ any(typeNeedsCx(a.type) for (a, _) in arguments) or
+ 'implicitJSContext' in extendedAttributes)
+
+ if not "cx" in argsPre and needsCx:
+ args.prepend(CGGeneric("cx"))
+
+ # Build up our actual call
+ self.cgRoot = CGList([], "\n")
+
+ call = CGGeneric(nativeMethodName)
+ if static:
+ call = CGWrapper(call, pre="%s::" % descriptorProvider.nativeType)
+ else:
+ call = CGWrapper(call, pre="(*%s)." % object)
+ call = CGList([call, CGWrapper(args, pre="(", post=");")])
+ if result is not None:
+ if declareResult:
+ result = CGWrapper(result, pre="let result: ", post=";")
+ self.cgRoot.prepend(result)
+ if not resultOutParam:
+ call = CGWrapper(call, pre="result = ")
+
+ call = CGWrapper(call)
+ self.cgRoot.append(call)
+
+ if isFallible:
+ self.cgRoot.prepend(CGGeneric("ErrorResult rv;"))
+ self.cgRoot.append(CGGeneric("if (rv.Failed()) {"))
+ self.cgRoot.append(CGIndenter(errorReport))
+ self.cgRoot.append(CGGeneric("}"))
+
+ def define(self):
+ return self.cgRoot.define()
+
+class MethodNotCreatorError(Exception):
+ def __init__(self, typename):
+ self.typename = typename
+
+class CGPerSignatureCall(CGThing):
+ """
+ This class handles the guts of generating code for a particular
+ call signature. A call signature consists of four things:
+
+ 1) A return type, which can be None to indicate that there is no
+ actual return value (e.g. this is an attribute setter) or an
+ IDLType if there's an IDL type involved (including |void|).
+ 2) An argument list, which is allowed to be empty.
+ 3) A name of a native method to call.
+ 4) Whether or not this method is static.
+
+ We also need to know whether this is a method or a getter/setter
+ to do error reporting correctly.
+
+ The idlNode parameter can be either a method or an attr. We can query
+ |idlNode.identifier| in both cases, so we can be agnostic between the two.
+ """
+ # XXXbz For now each entry in the argument list is either an
+ # IDLArgument or a FakeArgument, but longer-term we may want to
+ # have ways of flagging things like JSContext* or optional_argc in
+ # there.
+
+ def __init__(self, returnType, argsPre, arguments, nativeMethodName, static,
+ descriptor, idlNode, argConversionStartsAt=0,
+ getter=False, setter=False):
+ CGThing.__init__(self)
+ self.returnType = returnType
+ self.descriptor = descriptor
+ self.idlNode = idlNode
+ self.extendedAttributes = descriptor.getExtendedAttributes(idlNode,
+ getter=getter,
+ setter=setter)
+ self.argsPre = argsPre
+ self.arguments = arguments
+ self.argCount = len(arguments)
+ if self.argCount > argConversionStartsAt:
+ # Insert our argv in there
+ cgThings = [CGGeneric(self.getArgvDecl())]
+ else:
+ cgThings = []
+ cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(),
+ self.getArgc(), self.descriptor,
+ invalidEnumValueFatal=not setter) for
+ i in range(argConversionStartsAt, self.argCount)])
+
+ cgThings.append(CGCallGenerator(
+ self.getErrorReport() if self.isFallible() else None,
+ self.getArguments(), self.argsPre, returnType,
+ self.extendedAttributes, descriptor, nativeMethodName,
+ static))
+ self.cgRoot = CGList(cgThings, "\n")
+
+ def getArgv(self):
+ return "argv" if self.argCount > 0 else ""
+ def getArgvDecl(self):
+ return "\nargv: *jsval = JS_ARGV(cx, vp);\n"
+ def getArgc(self):
+ return "argc"
+ def getArguments(self):
+ return [(a, "arg" + str(i)) for (i, a) in enumerate(self.arguments)]
+
+ def isFallible(self):
+ return not 'infallible' in self.extendedAttributes
+
+ def wrap_return_value(self):
+ isCreator = memberIsCreator(self.idlNode)
+ if isCreator:
+ # We better be returning addrefed things!
+ #assert(isResultAlreadyAddRefed(self.descriptor,
+ # self.extendedAttributes) or
+ # Workers use raw pointers for new-object return
+ # values or something
+ # self.descriptor.workers)
+ pass
+
+ resultTemplateValues = { 'jsvalRef': '*vp', 'jsvalPtr': 'vp',
+ 'isCreator': isCreator}
+ try:
+ return wrapForType(self.returnType, self.descriptor,
+ resultTemplateValues)
+ except MethodNotCreatorError, err:
+ assert not isCreator
+ raise TypeError("%s being returned from non-creator method or property %s.%s" %
+ (err.typename,
+ self.descriptor.interface.identifier.name,
+ self.idlNode.identifier.name))
+
+ def getErrorReport(self):
+ return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'
+ % (toStringBool(not self.descriptor.workers),
+ self.descriptor.interface.identifier.name,
+ self.idlNode.identifier.name))
+
+ def define(self):
+ return (self.cgRoot.define() + "\n" + self.wrap_return_value())
+
+class CGGetterCall(CGPerSignatureCall):
+ """
+ A class to generate a native object getter call for a particular IDL
+ getter.
+ """
+ def __init__(self, returnType, nativeMethodName, descriptor, attr):
+ CGPerSignatureCall.__init__(self, returnType, [], [],
+ nativeMethodName, False, descriptor,
+ attr, getter=True)
+
+class CGAbstractBindingMethod(CGAbstractExternMethod):
+ """
+ Common class to generate the JSNatives for all our methods, getters, and
+ setters. This will generate the function declaration and unwrap the
+ |this| object. Subclasses are expected to override the generate_code
+ function to do the rest of the work. This function should return a
+ CGThing which is already properly indented.
+ """
+ def __init__(self, descriptor, name, args, unwrapFailureCode=None):
+ CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
+
+ if unwrapFailureCode is None:
+ self.unwrapFailureCode = ("return Throw<%s>(cx, rv);" %
+ toStringBool(not descriptor.workers))
+ else:
+ self.unwrapFailureCode = unwrapFailureCode
+
+ def definition_body(self):
+ # Our descriptor might claim that we're not castable, simply because
+ # we're someone's consequential interface. But for this-unwrapping, we
+ # know that we're the real deal. So fake a descriptor here for
+ # consumption by FailureFatalCastableObjectUnwrapper.
+ unwrapThis = CGIndenter(CGGeneric(
+ str(CastableObjectUnwrapper(
+ FakeCastableDescriptor(self.descriptor),
+ "obj", "self", self.unwrapFailureCode))))
+ return CGList([ self.getThis(), unwrapThis,
+ self.generate_code() ], "\n").define()
+
+ def getThis(self):
+ return CGIndenter(
+ CGGeneric("let obj: *JSObject = JS_THIS_OBJECT(cx, vp);\n"
+ "if obj.is_null() {\n"
+ " return false as JSBool;\n"
+ "}\n"
+ "\n"
+ "let self: *%s;" % self.descriptor.nativeType))
+
+ def generate_code(self):
+ assert(False) # Override me
+
+class CGGenericMethod(CGAbstractBindingMethod):
+ """
+ A class for generating the C++ code for an IDL method..
+ """
+ def __init__(self, descriptor):
+ args = [Argument('*JSContext', 'cx'), Argument('uint', 'argc'),
+ Argument('*jsval', 'vp')]
+ CGAbstractBindingMethod.__init__(self, descriptor, 'genericMethod', args)
+
+ def generate_code(self):
+ return CGIndenter(CGGeneric(
+ "let info: *JSJitInfo = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
+ "let method: JSJitMethodOp = (*info).op;\n"
+ "return method(cx, obj, self, argc, vp);"))
+
+class CGGenericGetter(CGAbstractBindingMethod):
+ """
+ A class for generating the C++ code for an IDL attribute getter.
+ """
+ def __init__(self, descriptor, lenientThis=False):
+ args = [Argument('*JSContext', 'cx'), Argument('uint', 'argc'),
+ Argument('*jsval', 'vp')]
+ if lenientThis:
+ name = "genericLenientGetter"
+ unwrapFailureCode = (
+ "MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"
+ "JS_SET_RVAL(cx, vp, JS::UndefinedValue());\n"
+ "return true;")
+ else:
+ name = "genericGetter"
+ unwrapFailureCode = None
+ CGAbstractBindingMethod.__init__(self, descriptor, name, args,
+ unwrapFailureCode)
+
+ def generate_code(self):
+ return CGIndenter(CGGeneric(
+ "let info: *JSJitInfo = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
+ "let getter: JSJitPropertyOp = (*info).op;\n"
+ "return getter(cx, obj, self, vp);"))
+
+class CGSpecializedGetter(CGAbstractExternMethod):
+ """
+ A class for generating the code for a specialized attribute getter
+ that the JIT can call with lower overhead.
+ """
+ def __init__(self, descriptor, attr):
+ self.attr = attr
+ name = 'get_' + attr.identifier.name
+ args = [ Argument('*JSContext', 'cx'),
+ Argument('*JSObject', 'obj'),
+ Argument('*%s' % descriptor.nativeType, 'self'),
+ Argument('*mut jsval', 'vp') ]
+ CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
+
+ def definition_body(self):
+ name = self.attr.identifier.name
+ nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
+ # resultOutParam does not depend on whether resultAlreadyAddRefed is set
+ (_, resultOutParam) = getRetvalDeclarationForType(self.attr.type,
+ self.descriptor,
+ False)
+ infallible = ('infallible' in
+ self.descriptor.getExtendedAttributes(self.attr,
+ getter=True))
+ if resultOutParam or self.attr.type.nullable() or not infallible:
+ nativeName = "Get" + nativeName
+ return CGIndenter(CGGetterCall(self.attr.type, nativeName,
+ self.descriptor, self.attr)).define()
+
+def infallibleForMember(member, type, descriptorProvider):
+ """
+ Determine the fallibility of changing a C++ value of IDL type "type" into
+ JS for the given attribute. Apart from isCreator, all the defaults are used,
+ since the fallbility does not change based on the boolean values,
+ and the template will be discarded.
+
+ CURRENT ASSUMPTIONS:
+ We assume that successCode for wrapping up return values cannot contain
+ failure conditions.
+ """
+ return getWrapTemplateForType(type, descriptorProvider, 'result', None,\
+ memberIsCreator(member))[1]
+
+class CGMemberJITInfo(CGThing):
+ """
+ A class for generating the JITInfo for a property that points to
+ our specialized getter and setter.
+ """
+ def __init__(self, descriptor, member):
+ self.member = member
+ self.descriptor = descriptor
+
+ def declare(self):
+ return ""
+
+ def defineJitInfo(self, infoName, opName, infallible):
+ protoID = "prototypes::id::%s" % self.descriptor.name
+ depth = "PrototypeTraits<%s>::Depth" % protoID
+ failstr = "true" if infallible else "false"
+ return ("\n"
+ "const %s: JSJitInfo = {\n"
+ " op: %s,\n"
+ " protoID: %s,\n"
+ " depth: %s,\n"
+ " isInfallible: %s, /* False in setters. */\n"
+ " isConstant: false /* Only relevant for getters. */\n"
+ "};\n" % (infoName, opName, protoID, depth, failstr))
+
+ def define(self):
+ if self.member.isAttr():
+ getterinfo = ("%s_getterinfo" % self.member.identifier.name)
+ getter = ("get_%s" % self.member.identifier.name)
+ getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
+ getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
+ result = self.defineJitInfo(getterinfo, getter, getterinfal)
+ if not self.member.readonly:
+ setterinfo = ("%s_setterinfo" % self.member.identifier.name)
+ setter = ("set_%s" % self.member.identifier.name)
+ # Setters are always fallible, since they have to do a typed unwrap.
+ result += self.defineJitInfo(setterinfo, setter, False)
+ return result
+ if self.member.isMethod():
+ methodinfo = ("%s_methodinfo" % self.member.identifier.name)
+ # Actually a JSJitMethodOp, but JSJitPropertyOp by struct definition.
+ method = ("%s" % self.member.identifier.name)
+
+ # Methods are infallible if they are infallible, have no arguments
+ # to unwrap, and have a return type that's infallible to wrap up for
+ # return.
+ methodInfal = False
+ sigs = self.member.signatures()
+ if len(sigs) == 1:
+ # Don't handle overloading. If there's more than one signature,
+ # one of them must take arguments.
+ sig = sigs[0]
+ if len(sig[1]) == 0 and infallibleForMember(self.member, sig[0], self.descriptor):
+ # No arguments and infallible return boxing
+ methodInfal = True
+
+ result = self.defineJitInfo(methodinfo, method, methodInfal)
+ return result
+ raise TypeError("Illegal member type to CGPropertyJITInfo")
+
+class CGAbstractClassHook(CGAbstractExternMethod):
+ """
+ Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
+ 'this' unwrapping as it assumes that the unwrapped type is always known.
+ """
+ def __init__(self, descriptor, name, returnType, args):
+ CGAbstractExternMethod.__init__(self, descriptor, name, returnType,
+ args)
+
+ def definition_body_prologue(self):
+ return """
+ %s* self = unwrap<%s>(obj);
+""" % (self.descriptor.nativeType, self.descriptor.nativeType)
+
+ def definition_body(self):
+ return self.definition_body_prologue() + self.generate_code()
+
+ def generate_code(self):
+ # Override me
+ assert(False)
+
+def finalizeHook(descriptor, hookName, context):
+ if descriptor.customFinalize:
+ return """if (self) {
+ self->%s(%s);
+}""" % (hookName, context)
+ #clearWrapper = "ClearWrapper(self, self);\n" if descriptor.wrapperCache else ""
+ if descriptor.workers:
+ release = "self->Release();"
+ else:
+ assert descriptor.nativeIsISupports
+ release = """let val = JS_GetReservedSlot(obj, 0);
+let _: %s = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val));
+""" % (descriptor.pointerType + descriptor.nativeType)
+ #return clearWrapper + release
+ return release
+
+class CGClassFinalizeHook(CGAbstractClassHook):
+ """
+ A hook for finalize, used to release our native object.
+ """
+ def __init__(self, descriptor):
+ args = [Argument('*JSFreeOp', 'fop'), Argument('*JSObject', 'obj')]
+ CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
+ 'void', args)
+
+ def generate_code(self):
+ return CGIndenter(CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))).define()
+
+class CGDescriptor(CGThing):
+ def __init__(self, descriptor):
+ CGThing.__init__(self)
+
+ assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
+
+ cgThings = []
+ if descriptor.interface.hasInterfacePrototypeObject():
+ (hasMethod, hasGetter, hasLenientGetter,
+ hasSetter, hasLenientSetter) = False, False, False, False, False
+ for m in descriptor.interface.members:
+ if m.isMethod() and not m.isStatic() and not m.isIdentifierLess():
+ #cgThings.append(CGSpecializedMethod(descriptor, m))
+ #cgThings.append(CGMemberJITInfo(descriptor, m))
+ hasMethod = True
+ elif m.isAttr():
+ cgThings.append(CGSpecializedGetter(descriptor, m))
+ if m.hasLenientThis():
+ hasLenientGetter = True
+ else:
+ hasGetter = True
+ if not m.readonly:
+ #cgThings.append(CGSpecializedSetter(descriptor, m))
+ if m.hasLenientThis():
+ hasLenientSetter = True
+ else:
+ hasSetter = True
+ cgThings.append(CGMemberJITInfo(descriptor, m))
+ #if hasMethod: cgThings.append(CGGenericMethod(descriptor))
+ if hasGetter: cgThings.append(CGGenericGetter(descriptor))
+ #if hasLenientGetter: cgThings.append(CGGenericGetter(descriptor,
+ # lenientThis=True))
+ #if hasSetter: cgThings.append(CGGenericSetter(descriptor))
+ #if hasLenientSetter: cgThings.append(CGGenericSetter(descriptor,
+ # lenientThis=True))
+
+ if descriptor.concrete and not descriptor.proxy:
+ if not descriptor.workers and descriptor.wrapperCache:
+ #cgThings.append(CGAddPropertyHook(descriptor))
+ pass
+
+ # Always have a finalize hook, regardless of whether the class wants a
+ # custom hook.
+ cgThings.append(CGClassFinalizeHook(descriptor))
+
+ # Only generate a trace hook if the class wants a custom hook.
+ if (descriptor.customTrace):
+ #cgThings.append(CGClassTraceHook(descriptor))
+ pass
+
+ if descriptor.interface.hasInterfaceObject():
+ #cgThings.append(CGClassConstructHook(descriptor))
+ #cgThings.append(CGClassHasInstanceHook(descriptor))
+ #cgThings.append(CGInterfaceObjectJSClass(descriptor))
+ pass
+
+ if descriptor.interface.hasInterfacePrototypeObject():
+ #cgThings.append(CGPrototypeJSClass(descriptor))
+ pass
+
+ properties = PropertyArrays(descriptor)
+ #cgThings.append(CGGeneric(define=str(properties)))
+ #cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
+ if descriptor.interface.hasInterfacePrototypeObject():
+ #cgThings.append(CGGetProtoObjectMethod(descriptor))
+ pass
+ else:
+ #cgThings.append(CGGetConstructorObjectMethod(descriptor))
+ pass
+
+ # Set up our Xray callbacks as needed. Note that we don't need to do
+ # it in workers.
+ if (descriptor.interface.hasInterfacePrototypeObject() and
+ not descriptor.workers):
+ if descriptor.concrete and descriptor.proxy:
+ #cgThings.append(CGResolveOwnProperty(descriptor))
+ #cgThings.append(CGEnumerateOwnProperties(descriptor))
+ pass
+ #cgThings.append(CGResolveProperty(descriptor, properties))
+ #cgThings.append(CGEnumerateProperties(descriptor, properties))
+
+ if descriptor.interface.hasInterfaceObject():
+ #cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
+ if (not descriptor.interface.isExternal() and
+ # Workers stuff is never pref-controlled
+ not descriptor.workers and
+ descriptor.interface.getExtendedAttribute("PrefControlled") is not None):
+ #cgThings.append(CGPrefEnabled(descriptor))
+ pass
+
+ if descriptor.interface.hasInterfacePrototypeObject():
+ #cgThings.append(CGNativePropertyHooks(descriptor))
+ pass
+
+ if descriptor.concrete:
+ if descriptor.proxy:
+ #cgThings.append(CGProxyIsProxy(descriptor))
+ #cgThings.append(CGProxyUnwrap(descriptor))
+ #cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
+ #cgThings.append(CGDOMJSProxyHandler(descriptor))
+ #cgThings.append(CGIsMethod(descriptor))
+ pass
+ else:
+ #cgThings.append(CGDOMJSClass(descriptor))
+ pass
+
+ if descriptor.wrapperCache:
+ #cgThings.append(CGWrapWithCacheMethod(descriptor))
+ #cgThings.append(CGWrapMethod(descriptor))
+ pass
+ else:
+ #cgThings.append(CGWrapNonWrapperCacheMethod(descriptor))
+ pass
+
+ cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
+ cgThings = CGWrapper(cgThings, pre='\n', post='\n')
+ #self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
+ # cgThings),
+ # post='\n')
+ self.cgRoot = cgThings
+
+ def declare(self):
+ return self.cgRoot.declare()
+ def define(self):
+ return self.cgRoot.define()
+
+class CGBindingRoot(CGThing):
+ """
+ Root codegen class for binding generation. Instantiate the class, and call
+ declare or define to generate header or cpp code (respectively).
+ """
+ def __init__(self, config, prefix, webIDLFile):
+ descriptors = config.getDescriptors(webIDLFile=webIDLFile,
+ hasInterfaceOrInterfacePrototypeObject=True)
+ dictionaries = config.getDictionaries(webIDLFile)
+
+ cgthings = []
+
+ # Do codegen for all the descriptors
+ cgthings.extend([CGDescriptor(x) for x in descriptors])
+
+ # And make sure we have the right number of newlines at the end
+ curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
+
+ # Wrap all of that in our namespaces.
+ #curr = CGNamespace.build(['dom'],
+ # CGWrapper(curr, pre="\n"))
+
+ # Add imports
+ curr = CGImports(descriptors,
+ dictionaries,
+ [],
+ ['js::*',
+ 'js::jsapi::*',
+ 'js::jsapi::bindgen::*',
+ 'js::glue::bindgen::*',
+ 'dom::bindings::utils::*'],
+ curr)
+
+ # Add the auto-generated comment.
+ curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
+
+ # Store the final result.
+ self.root = curr
+ def declare(self):
+ return stripTrailingWhitespace(self.root.declare())
+ def define(self):
+ return stripTrailingWhitespace(self.root.define())