Merge central to inbound
authorMarco Bonardo <mbonardo@mozilla.com>
Fri, 30 Mar 2012 12:27:55 +0200
changeset 90689 7bfb26afd19b6ac4ab99b646e7972969954441a5
parent 90688 461760e5dbd591abf0b943e89ca9cabad2485ecf (current diff)
parent 90627 0d696f3bb8872799522444a558883e094faf8675 (diff)
child 90690 0cfa44a13b2513ad09075ef9da2a062ce40c9576
child 90727 2c4ec30ee406ca847eed74b259fc8a44cac0f053
push id650
push usertim.taubert@gmx.de
push dateFri, 30 Mar 2012 16:31:11 +0000
treeherderfx-team@945faa47b627 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone14.0a1
Merge central to inbound
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/xul/document/src/nsXULDocument.cpp
dom/base/nsGlobalWindow.cpp
gfx/thebes/gfxAtomList.h
gfx/thebes/gfxAtoms.cpp
gfx/thebes/gfxAtoms.h
gfx/thebes/gfxFont.cpp
testing/mochitest/tests/SimpleTest/specialpowersAPI.js
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -89,16 +89,21 @@ ifdef MOZ_ANGLE
 DEFINES += -DMOZ_ANGLE=$(MOZ_ANGLE)
 DEFINES += -DMOZ_D3DX9_DLL=$(MOZ_D3DX9_DLL)
 DEFINES += -DMOZ_D3DCOMPILER_DLL=$(MOZ_D3DCOMPILER_DLL)
 endif
 
 include $(topsrcdir)/ipc/app/defs.mk
 DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
+# Set MSVC dlls version to package, if any.
+ifdef WIN32_REDIST_DIR
+DEFINES += -DMOZ_MSVC_REDIST=$(_MSC_VER)
+endif
+
 ifneq (,$(filter aurora beta,$(MOZ_UPDATE_CHANNEL)))
 DEFINES += -DSHIP_FEEDBACK=1
 endif
 
 ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
 DEFINES += -DMOZ_SHARED_MOZGLUE=1
 endif
 
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -65,30 +65,30 @@
 #ifdef XP_MACOSX
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@.app/
 @BINPATH@/@DLL_PREFIX@plugin_child_interpose@DLL_SUFFIX@
 #else
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@
 #endif
 #ifdef XP_WIN32
 #ifndef MOZ_DEBUG
-#if _MSC_VER == 1400
+#if MOZ_MSVC_REDIST == 1400
 @BINPATH@/Microsoft.VC80.CRT.manifest
 @BINPATH@/msvcm80.dll
 @BINPATH@/msvcp80.dll
 @BINPATH@/msvcr80.dll
-#elif _MSC_VER == 1500
+#elif MOZ_MSVC_REDIST == 1500
 @BINPATH@/Microsoft.VC90.CRT.manifest
 @BINPATH@/msvcm90.dll
 @BINPATH@/msvcp90.dll
 @BINPATH@/msvcr90.dll
-#elif _MSC_VER == 1600
+#elif MOZ_MSVC_REDIST == 1600
 @BINPATH@/msvcp100.dll
 @BINPATH@/msvcr100.dll
-#elif _MSC_VER == 1700
+#elif MOZ_MSVC_REDIST == 1700
 @BINPATH@/msvcp110.dll
 @BINPATH@/msvcr110.dll
 #endif
 #endif
 #endif
 
 [browser]
 ; [Base Browser Files]
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -1347,39 +1347,39 @@ xpicleanup@BIN_SUFFIX@
 #ifndef XP_WIN
   res/fonts/mathfontSymbol.properties
 #endif
 #ifdef XP_WIN
   components/brwsrcmp.dll
   components/jsd3250.dll
   components/nsPostUpdateWin.js
   js3250.dll
-  plugins/npnul32.dll
-  #if _MSC_VER != 1400
+  mozcpp19.dll
+  mozcrt19.dll
+  #if MOZ_MSVC_REDIST != 1400
     Microsoft.VC80.CRT.manifest
     msvcm80.dll
     msvcp80.dll
     msvcr80.dll
   #endif
-  #if _MSC_VER != 1500
+  #if MOZ_MSVC_REDIST != 1500
     Microsoft.VC90.CRT.manifest
     msvcm90.dll
     msvcp90.dll
     msvcr90.dll
   #endif
-  #if _MSC_VER != 1600
+  #if MOZ_MSVC_REDIST != 1600
     msvcp100.dll
     msvcr100.dll
   #endif
-  #if _MSC_VER != 1700
+  #if MOZ_MSVC_REDIST != 1700
     msvcp110.dll
     msvcr110.dll
   #endif
-  mozcrt19.dll
-  mozcpp19.dll
+  plugins/npnul32.dll
 #endif
 @DLL_PREFIX@xpcom_core@DLL_SUFFIX@
 components/@DLL_PREFIX@jar50@DLL_SUFFIX@
 #ifdef XP_WIN
   components/xpinstal.dll
 #else
   components/@DLL_PREFIX@jsd@DLL_SUFFIX@
   components/@DLL_PREFIX@xpinstall@DLL_SUFFIX@
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1282,78 +1282,22 @@ public:
   static void DestroyMatchString(void* aData)
   {
     if (aData) {
       nsString* matchString = static_cast<nsString*>(aData);
       delete matchString;
     }
   }
 
-  static void DropScriptObject(PRUint32 aLangID, void *aObject,
-                               const char *name, void *aClosure)
-  {
-    DropScriptObject(aLangID, aObject, aClosure);
-  }
-
   /**
    * Unbinds the content from the tree and nulls it out if it's not null.
    */
   static void DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent);
 
   /**
-   * Keep script object aNewObject, held by aScriptObjectHolder, alive.
-   *
-   * NOTE: This currently only supports objects that hold script objects of one
-   *       scripting language.
-   *
-   * @param aLangID script language ID of aNewObject
-   * @param aScriptObjectHolder the object that holds aNewObject
-   * @param aTracer the tracer for aScriptObject
-   * @param aNewObject the script object to hold
-   * @param aWasHoldingObjects whether aScriptObjectHolder was already holding
-   *                           script objects (ie. HoldScriptObject was called
-   *                           on it before, without a corresponding call to
-   *                           DropScriptObjects)
-   */
-  static nsresult HoldScriptObject(PRUint32 aLangID, void* aScriptObjectHolder,
-                                   nsScriptObjectTracer* aTracer,
-                                   void* aNewObject, bool aWasHoldingObjects)
-  {
-    if (aLangID == nsIProgrammingLanguage::JAVASCRIPT) {
-      return aWasHoldingObjects ? NS_OK :
-                                  HoldJSObjects(aScriptObjectHolder, aTracer);
-    }
-
-    return HoldScriptObject(aLangID, aNewObject);
-  }
-
-  /**
-   * Drop any script objects that aScriptObjectHolder is holding.
-   *
-   * NOTE: This currently only supports objects that hold script objects of one
-   *       scripting language.
-   *
-   * @param aLangID script language ID of the objects that 
-   * @param aScriptObjectHolder the object that holds script object that we want
-   *                            to drop
-   * @param aTracer the tracer for aScriptObject
-   */
-  static nsresult DropScriptObjects(PRUint32 aLangID, void* aScriptObjectHolder,
-                                    nsScriptObjectTracer* aTracer)
-  {
-    if (aLangID == nsIProgrammingLanguage::JAVASCRIPT) {
-      return DropJSObjects(aScriptObjectHolder);
-    }
-
-    aTracer->Trace(aScriptObjectHolder, DropScriptObject, nsnull);
-
-    return NS_OK;
-  }
-
-  /**
    * Keep the JS objects held by aScriptObjectHolder alive.
    *
    * @param aScriptObjectHolder the object that holds JS objects that we want to
    *                            keep alive
    * @param aTracer the tracer for aScriptObject
    */
   static nsresult HoldJSObjects(void* aScriptObjectHolder,
                                 nsScriptObjectTracer* aTracer);
@@ -2058,21 +2002,16 @@ public:
   static void SplitMimeType(const nsAString& aValue, nsString& aType,
                             nsString& aParams);
 
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
-  static nsIDOMScriptObjectFactory *GetDOMScriptObjectFactory();
-
-  static nsresult HoldScriptObject(PRUint32 aLangID, void* aObject);
-  static void DropScriptObject(PRUint32 aLangID, void *aObject, void *aClosure);
-
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
   static nsresult WrapNative(JSContext *cx, JSObject *scope,
                              nsISupports *native, nsWrapperCache *cache,
                              const nsIID* aIID, jsval *vp,
                              nsIXPConnectJSObjectHolder** aHolder,
                              bool aAllowWrapping);
@@ -2124,18 +2063,16 @@ private:
   static nsIStringBundle* sStringBundles[PropertiesFile_COUNT];
 
   static nsIContentPolicy* sContentPolicyService;
   static bool sTriedToGetContentPolicy;
 
   static nsILineBreaker* sLineBreaker;
   static nsIWordBreaker* sWordBreaker;
 
-  static nsIScriptRuntime* sScriptRuntimes[NS_STID_ARRAY_UBOUND];
-  static PRInt32 sScriptRootCount[NS_STID_ARRAY_UBOUND];
   static PRUint32 sJSGCThingRootCount;
 
 #ifdef IBMBIDI
   static nsIBidiKeyboard* sBidiKeyboard;
 #endif
 
   static bool sInitialized;
   static PRUint32 sScriptBlockerCount;
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -522,17 +522,17 @@ public:
    * it is simply null;
    */
   virtual const nsTextFragment *GetText() = 0;
 
   /**
    * Get the length of the text content.
    * NOTE: This should not be called on elements.
    */
-  virtual PRUint32 TextLength() = 0;
+  virtual PRUint32 TextLength() const = 0;
 
   /**
    * Set the text to the given value. If aNotify is true then
    * the document is notified of the content change.
    * NOTE: For elements this always ASSERTS and returns NS_ERROR_FAILURE
    */
   virtual nsresult SetText(const PRUnichar* aBuffer, PRUint32 aLength,
                            bool aNotify) = 0;
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -286,18 +286,18 @@ private:
 // Categories of node properties
 // 0 is global.
 #define DOM_USER_DATA         1
 #define DOM_USER_DATA_HANDLER 2
 #define SMIL_MAPPED_ATTR_ANIMVAL 3
 
 // IID for the nsINode interface
 #define NS_INODE_IID \
-{ 0xfcd3b0d1, 0x75db, 0x46c4, \
-  { 0xa1, 0xf5, 0x07, 0xc2, 0x09, 0xf8, 0x1f, 0x44 } }
+{ 0x458300ed, 0xe418, 0x4577, \
+  { 0x89, 0xd7, 0xfe, 0xf1, 0x34, 0xf3, 0x52, 0x19 } }
 
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
  * nsIContent and nsIDocument share.  An instance of this interface has a list
  * of nsIContent children and provides access to them.
  */
 class nsINode : public nsIDOMEventTarget,
                 public nsWrapperCache
@@ -582,22 +582,20 @@ public:
   /**
    * Remove a child from this node.  This method handles calling UnbindFromTree
    * on the child appropriately.
    *
    * @param aIndex the index of the child to remove
    * @param aNotify whether to notify the document (current document for
    *        nsIContent, and |this| for nsIDocument) that the remove has
    *        occurred
-   * @param aMutationEvent whether to fire a mutation event
    *
    * Note: If there is no child at aIndex, this method will simply do nothing.
    */
-  virtual nsresult RemoveChildAt(PRUint32 aIndex, 
-                                 bool aNotify) = 0;
+  virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify) = 0;
 
   /**
    * Get a property associated with this node.
    *
    * @param aPropertyName  name of property to get.
    * @param aStatus        out parameter for storing resulting status.
    *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
    *                       is not set.
@@ -1418,16 +1416,22 @@ protected:
   {
     mSubtreeRoot = nsnull;
   }
 
 public:
   // Optimized way to get classinfo.
   virtual nsXPCClassInfo* GetClassInfo() = 0;
 
+  /**
+   * Returns the length of this node, as specified at
+   * <http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length>
+   */
+  PRUint32 Length() const;
+
 protected:
 
   // Override this function to create a custom slots class.
   virtual nsINode::nsSlots* CreateSlots();
 
   bool HasSlots() const
   {
     return mSlots != nsnull;
@@ -1502,18 +1506,18 @@ protected:
    * nodes.  The aChildArray passed in should be the one for |this|.
    *
    * @param aIndex The index to remove at.
    * @param aNotify Whether to notify.
    * @param aKid The kid at aIndex.  Must not be null.
    * @param aChildArray The child array to work with.
    * @param aMutationEvent whether to fire a mutation event for this removal.
    */
-  nsresult doRemoveChildAt(PRUint32 aIndex, bool aNotify, nsIContent* aKid,
-                           nsAttrAndChildArray& aChildArray);
+  void doRemoveChildAt(PRUint32 aIndex, bool aNotify, nsIContent* aKid,
+                       nsAttrAndChildArray& aChildArray);
 
   /**
    * Most of the implementation of the nsINode InsertChildAt method.
    * Should only be called on document, element, and document fragment
    * nodes.  The aChildArray passed in should be the one for |this|.
    *
    * @param aKid The child to insert.
    * @param aIndex The index to insert at.
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -258,18 +258,16 @@ nsDataHashtable<nsISupportsHashKey, Even
 nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nsnull;
 nsCOMArray<nsIAtom>* nsContentUtils::sUserDefinedEvents = nsnull;
 nsIStringBundleService *nsContentUtils::sStringBundleService;
 nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT];
 nsIContentPolicy *nsContentUtils::sContentPolicyService;
 bool nsContentUtils::sTriedToGetContentPolicy = false;
 nsILineBreaker *nsContentUtils::sLineBreaker;
 nsIWordBreaker *nsContentUtils::sWordBreaker;
-nsIScriptRuntime *nsContentUtils::sScriptRuntimes[NS_STID_ARRAY_UBOUND];
-PRInt32 nsContentUtils::sScriptRootCount[NS_STID_ARRAY_UBOUND];
 PRUint32 nsContentUtils::sJSGCThingRootCount;
 #ifdef IBMBIDI
 nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nsnull;
 #endif
 PRUint32 nsContentUtils::sScriptBlockerCount = 0;
 #ifdef DEBUG
 PRUint32 nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
 #endif
@@ -4326,79 +4324,16 @@ void
 nsContentUtils::DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent)
 {
   if (*aContent) {
     AddScriptRunner(new AnonymousContentDestroyer(aContent));
   }
 }
 
 /* static */
-nsIDOMScriptObjectFactory*
-nsContentUtils::GetDOMScriptObjectFactory()
-{
-  if (!sDOMScriptObjectFactory) {
-    static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
-                         NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
-
-    CallGetService(kDOMScriptObjectFactoryCID, &sDOMScriptObjectFactory);
-  }
-
-  return sDOMScriptObjectFactory;
-}
-
-/* static */
-nsresult
-nsContentUtils::HoldScriptObject(PRUint32 aLangID, void *aObject)
-{
-  NS_ASSERTION(aObject, "unexpected null object");
-  NS_ASSERTION(aLangID != nsIProgrammingLanguage::JAVASCRIPT,
-               "Should use HoldJSObjects.");
-  nsresult rv;
-
-  PRUint32 langIndex = NS_STID_INDEX(aLangID);
-  nsIScriptRuntime *runtime = sScriptRuntimes[langIndex];
-  if (!runtime) {
-    nsIDOMScriptObjectFactory *factory = GetDOMScriptObjectFactory();
-    NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
-
-    rv = factory->GetScriptRuntimeByID(aLangID, &runtime);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // This makes sScriptRuntimes hold a strong ref.
-    sScriptRuntimes[langIndex] = runtime;
-  }
-
-  rv = runtime->HoldScriptObject(aObject);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  ++sScriptRootCount[langIndex];
-  NS_LOG_ADDREF(sScriptRuntimes[langIndex], sScriptRootCount[langIndex],
-                "HoldScriptObject", sizeof(void*));
-
-  return NS_OK;
-}
-
-/* static */
-void
-nsContentUtils::DropScriptObject(PRUint32 aLangID, void *aObject,
-                                 void *aClosure)
-{
-  NS_ASSERTION(aObject, "unexpected null object");
-  NS_ASSERTION(aLangID != nsIProgrammingLanguage::JAVASCRIPT,
-               "Should use DropJSObjects.");
-  PRUint32 langIndex = NS_STID_INDEX(aLangID);
-  NS_LOG_RELEASE(sScriptRuntimes[langIndex], sScriptRootCount[langIndex] - 1,
-                 "HoldScriptObject");
-  sScriptRuntimes[langIndex]->DropScriptObject(aObject);
-  if (--sScriptRootCount[langIndex] == 0) {
-    NS_RELEASE(sScriptRuntimes[langIndex]);
-  }
-}
-
-/* static */
 nsresult
 nsContentUtils::HoldJSObjects(void* aScriptObjectHolder,
                               nsScriptObjectTracer* aTracer)
 {
   NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED);
 
   nsresult rv = sXPConnect->AddJSHolder(aScriptObjectHolder, aTracer);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/content/base/src/nsDOMAttribute.cpp
+++ b/content/base/src/nsDOMAttribute.cpp
@@ -692,29 +692,28 @@ nsDOMAttribute::InsertChildAt(nsIContent
 }
 
 nsresult
 nsDOMAttribute::AppendChildTo(nsIContent* aKid, bool aNotify)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-nsresult
+void
 nsDOMAttribute::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
   if (aIndex != 0 || !mChild) {
-    return NS_OK;
+    return;
   }
 
   doRemoveChild(aNotify);
 
   nsString nullString;
   SetDOMStringToNull(nullString);
   SetValue(nullString);
-  return NS_OK;
 }
 
 nsresult
 nsDOMAttribute::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
   return NS_OK;
 }
--- a/content/base/src/nsDOMAttribute.h
+++ b/content/base/src/nsDOMAttribute.h
@@ -85,17 +85,17 @@ public:
   virtual bool IsNodeOfType(PRUint32 aFlags) const;
   virtual PRUint32 GetChildCount() const;
   virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
   virtual nsIContent * const * GetChildArray(PRUint32* aChildCount) const;
   virtual PRInt32 IndexOf(nsINode* aPossibleChild) const;
   virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                                  bool aNotify);
   virtual nsresult AppendChildTo(nsIContent* aKid, bool aNotify);
-  virtual nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
+  virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify);
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual already_AddRefed<nsIURI> GetBaseURI() const;
 
   static void Initialize();
   static void Shutdown();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDOMAttribute,
                                                          nsIAttribute)
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -3509,33 +3509,31 @@ nsDocument::AppendChildTo(nsIContent* aK
   // Make sure to _not_ call the subclass InsertChildAt here.  If
   // subclasses wanted to hook into this stuff, they would have
   // overridden AppendChildTo.
   // XXXbz maybe this should just be a non-virtual method on nsINode?
   // Feels that way to me...
   return nsDocument::InsertChildAt(aKid, GetChildCount(), aNotify);
 }
 
-nsresult
+void
 nsDocument::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
   nsCOMPtr<nsIContent> oldKid = GetChildAt(aIndex);
   if (!oldKid) {
-    return NS_OK;
+    return;
   }
 
   if (oldKid->IsElement()) {
     // Destroy the link map up front before we mess with the child list.
     DestroyElementMaps();
   }
 
-  nsresult rv =
-    doRemoveChildAt(aIndex, aNotify, oldKid, mChildren);
+  doRemoveChildAt(aIndex, aNotify, oldKid, mChildren);
   mCachedRootElement = nsnull;
-  return rv;
 }
 
 PRInt32
 nsDocument::GetNumberOfStyleSheets() const
 {
   return mStyleSheets.Count();
 }
 
@@ -5981,17 +5979,16 @@ BlastFunc(nsAttrHashKey::KeyType aKey, n
                "non-nsIAttribute somehow made it into the hashmap?!");
 
   return PL_DHASH_STOP;
 }
 
 static void
 BlastSubtreeToPieces(nsINode *aNode)
 {
-  PRUint32 i, count;
   if (aNode->IsElement()) {
     nsGenericElement *element = static_cast<nsGenericElement*>(aNode);
     const nsDOMAttributeMap *map = element->GetAttributeMap();
     if (map) {
       nsCOMPtr<nsIAttribute> attr;
       while (map->Enumerate(BlastFunc, &attr) > 0) {
         BlastSubtreeToPieces(attr);
 
@@ -6003,26 +6000,20 @@ BlastSubtreeToPieces(nsINode *aNode)
                              false);
 
         // XXX Should we abort here?
         NS_ASSERTION(NS_SUCCEEDED(rv), "Uhoh, UnsetAttr shouldn't fail!");
       }
     }
   }
 
-  count = aNode->GetChildCount();
-  for (i = 0; i < count; ++i) {
+  PRUint32 count = aNode->GetChildCount();
+  for (PRUint32 i = 0; i < count; ++i) {
     BlastSubtreeToPieces(aNode->GetFirstChild());
-#ifdef DEBUG
-    nsresult rv =
-#endif
-      aNode->RemoveChildAt(0, false);
-
-    // XXX Should we abort here?
-    NS_ASSERTION(NS_SUCCEEDED(rv), "Uhoh, RemoveChildAt shouldn't fail!");
+    aNode->RemoveChildAt(0, false);
   }
 }
 
 
 class nsUserDataCaller : public nsRunnable
 {
 public:
   nsUserDataCaller(nsCOMArray<nsINode>& aNodesWithProperties,
@@ -6116,18 +6107,17 @@ nsDocument::AdoptNode(nsIDOMNode *aAdopt
             return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
           }
         }
       } while ((doc = doc->GetParentDocument()));
 
       // Remove from parent.
       nsCOMPtr<nsINode> parent = adoptedNode->GetNodeParent();
       if (parent) {
-        rv = parent->RemoveChildAt(parent->IndexOf(adoptedNode), true);
-        NS_ENSURE_SUCCESS(rv, rv);
+        parent->RemoveChildAt(parent->IndexOf(adoptedNode), true);
       }
 
       break;
     }
     case nsIDOMNode::ENTITY_REFERENCE_NODE:
     {
       return NS_ERROR_NOT_IMPLEMENTED;
     }
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -719,17 +719,17 @@ public:
   virtual void NodeName(nsAString& aNodeName);
   virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
   virtual nsIContent * const * GetChildArray(PRUint32* aChildCount) const;
   virtual PRInt32 IndexOf(nsINode* aPossibleChild) const;
   virtual PRUint32 GetChildCount() const;
   virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                                  bool aNotify);
   virtual nsresult AppendChildTo(nsIContent* aKid, bool aNotify);
-  virtual nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
+  virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify);
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // nsIRadioGroupContainer
   NS_IMETHOD WalkRadioGroup(const nsAString& aName,
                             nsIRadioVisitor* aVisitor,
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -737,42 +737,16 @@ static nsresult GetNextNode(nsIDOMNode* 
 }
 #endif
 
 static bool IsTextNode(nsINode *aNode)
 {
   return aNode && aNode->IsNodeOfType(nsINode::eTEXT);
 }
 
-static nsresult GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount) 
-{
-  aCount = 0;
-  if (!aNode) { return NS_ERROR_NULL_POINTER; }
-  nsresult result=NS_OK;
-  nsCOMPtr<nsIDOMCharacterData>nodeAsChar;
-  nodeAsChar = do_QueryInterface(aNode);
-  if (nodeAsChar) {
-    nodeAsChar->GetLength(&aCount);
-  }
-  else
-  {
-    bool hasChildNodes;
-    aNode->HasChildNodes(&hasChildNodes);
-    if (true==hasChildNodes)
-    {
-      nsCOMPtr<nsIDOMNodeList>nodeList;
-      result = aNode->GetChildNodes(getter_AddRefs(nodeList));
-      if (NS_SUCCEEDED(result) && nodeList) {
-        nodeList->GetLength(&aCount);
-      }
-    }
-  }
-  return result;
-}
-
 nsresult
 nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
                                        nsINode* aNode,
                                        nsAString& aString,
                                        PRInt32 aDepth)
 {
   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
   NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
@@ -1694,23 +1668,22 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endp
   
   if (aWhere == kEnd)
   {
     // some special casing for text nodes
     nsCOMPtr<nsINode> n = do_QueryInterface(aNode);
     if (IsTextNode(n))
     {
       // if not at end of text node, we are done
-      PRUint32 len;
-      GetLengthOfDOMNode(aNode, len);
+      PRUint32 len = n->Length();
       if (offset < (PRInt32)len)
       {
         // unless everything after us in just whitespace.  NOTE: we need a more
         // general solution that truly detects all cases of non-significant
-        // whitesace with no false alarms.
+        // whitespace with no false alarms.
         nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
         nsAutoString text;
         nodeAsText->SubstringData(offset, len-offset, text);
         text.CompressWhitespace();
         if (!text.IsEmpty())
           return NS_OK;
         bResetPromotion = true;
       }
@@ -1886,28 +1859,30 @@ nsHTMLCopyEncoder::IsFirstNode(nsIDOMNod
 }
 
 
 bool
 nsHTMLCopyEncoder::IsLastNode(nsIDOMNode *aNode)
 {
   nsCOMPtr<nsIDOMNode> parent;
   PRInt32 offset,j;
-  PRUint32 numChildren;
   nsresult rv = GetNodeLocation(aNode, address_of(parent), &offset);
   if (NS_FAILED(rv)) 
   {
     NS_NOTREACHED("failure in IsLastNode");
     return false;
   }
-  GetLengthOfDOMNode(parent, numChildren); 
+  nsCOMPtr<nsINode> parentNode = do_QueryInterface(parent);
+  if (!parentNode) {
+    return true;
+  }
+
+  PRUint32 numChildren = parentNode->Length();
   if (offset+1 == (PRInt32)numChildren) // easy case, we are last dom child
     return true;
-  if (!parent)
-    return true;
   // need to check if any nodes after us are really visible.
   // Mike wrote something for me along these lines in nsSelectionController,
   // but I don't think it's ready for use yet - revisit.
   // HACK: for now, simply consider all whitespace text nodes to be 
   // invisible formatting nodes.
   j = (PRInt32)numChildren-1;
   nsCOMPtr<nsIDOMNodeList>childList;
   nsCOMPtr<nsIDOMNode> child;
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -675,20 +675,19 @@ nsGenericDOMDataNode::IndexOf(nsINode* a
 
 nsresult
 nsGenericDOMDataNode::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                                     bool aNotify)
 {
   return NS_OK;
 }
 
-nsresult
+void
 nsGenericDOMDataNode::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
-  return NS_OK;
 }
 
 nsIContent *
 nsGenericDOMDataNode::GetBindingParent() const
 {
   nsDataSlots *slots = GetExistingDataSlots();
   return slots ? slots->mBindingParent : nsnull;
 }
@@ -869,17 +868,17 @@ nsGenericDOMDataNode::GetWholeText(nsASt
 
 const nsTextFragment *
 nsGenericDOMDataNode::GetText()
 {
   return &mText;
 }
 
 PRUint32
-nsGenericDOMDataNode::TextLength()
+nsGenericDOMDataNode::TextLength() const
 {
   return mText.GetLength();
 }
 
 nsresult
 nsGenericDOMDataNode::SetText(const PRUnichar* aBuffer,
                               PRUint32 aLength,
                               bool aNotify)
--- a/content/base/src/nsGenericDOMDataNode.h
+++ b/content/base/src/nsGenericDOMDataNode.h
@@ -165,17 +165,17 @@ public:
 
   // nsINode methods
   virtual PRUint32 GetChildCount() const;
   virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
   virtual nsIContent * const * GetChildArray(PRUint32* aChildCount) const;
   virtual PRInt32 IndexOf(nsINode* aPossibleChild) const;
   virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                                  bool aNotify);
-  virtual nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
+  virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify);
   NS_IMETHOD GetTextContent(nsAString &aTextContent)
   {
     nsresult rv = GetNodeValue(aTextContent);
     NS_ASSERTION(NS_SUCCEEDED(rv), "GetNodeValue() failed?");
     return rv;
   }
   NS_IMETHOD SetTextContent(const nsAString& aTextContent)
   {
@@ -206,17 +206,17 @@ public:
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify);
   virtual bool GetAttr(PRInt32 aNameSpaceID, nsIAtom *aAttribute,
                          nsAString& aResult) const;
   virtual bool HasAttr(PRInt32 aNameSpaceID, nsIAtom *aAttribute) const;
   virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const;
   virtual PRUint32 GetAttrCount() const;
   virtual const nsTextFragment *GetText();
-  virtual PRUint32 TextLength();
+  virtual PRUint32 TextLength() const;
   virtual nsresult SetText(const PRUnichar* aBuffer, PRUint32 aLength,
                            bool aNotify);
   // Need to implement this here too to avoid hiding.
   nsresult SetText(const nsAString& aStr, bool aNotify)
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
   virtual nsresult AppendText(const PRUnichar* aBuffer, PRUint32 aLength,
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -530,17 +530,18 @@ nsINode::RemoveChild(nsINode *aOldChild)
   }
 
   PRInt32 index = IndexOf(aOldChild);
   if (index == -1) {
     // aOldChild isn't one of our children.
     return NS_ERROR_DOM_NOT_FOUND_ERR;
   }
 
-  return RemoveChildAt(index, true);
+  RemoveChildAt(index, true);
+  return NS_OK;
 }
 
 nsresult
 nsINode::ReplaceOrInsertBefore(bool aReplace, nsIDOMNode* aNewChild,
                                nsIDOMNode* aRefChild, nsIDOMNode** aReturn)
 {
   nsCOMPtr<nsINode> newChild = do_QueryInterface(aNewChild);
 
@@ -3843,30 +3844,28 @@ nsINode::doInsertChildAt(nsIContent* aKi
       mozAutoSubtreeModified subtree(OwnerDoc(), this);
       (new nsAsyncDOMEvent(aKid, mutation))->RunDOMEventWhenSafe();
     }
   }
 
   return NS_OK;
 }
 
-nsresult
+void
 nsGenericElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
   nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
   NS_ASSERTION(oldKid == GetChildAt(aIndex), "Unexpected child in RemoveChildAt");
 
   if (oldKid) {
-    return doRemoveChildAt(aIndex, aNotify, oldKid, mAttrsAndChildren);
-  }
-
-  return NS_OK;
-}
-
-nsresult
+    doRemoveChildAt(aIndex, aNotify, oldKid, mAttrsAndChildren);
+  }
+}
+
+void
 nsINode::doRemoveChildAt(PRUint32 aIndex, bool aNotify,
                          nsIContent* aKid, nsAttrAndChildArray& aChildArray)
 {
   NS_PRECONDITION(aKid && aKid->GetNodeParent() == this &&
                   aKid == GetChildAt(aIndex) &&
                   IndexOf(aKid) == (PRInt32)aIndex, "Bogus aKid");
 
   nsMutationGuard::DidMutate();
@@ -3883,18 +3882,16 @@ nsINode::doRemoveChildAt(PRUint32 aIndex
 
   aChildArray.RemoveChildAt(aIndex);
 
   if (aNotify) {
     nsNodeUtils::ContentRemoved(this, aKid, aIndex, previousSibling);
   }
 
   aKid->UnbindFromTree();
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGenericElement::GetTextContent(nsAString &aTextContent)
 {
   nsContentUtils::GetNodeTextContent(this, true, aTextContent);
   return NS_OK;
 }
@@ -4268,22 +4265,19 @@ nsINode::ReplaceOrInsertBefore(bool aRep
     insPos = GetChildCount();
   }
 
   // Make sure that the inserted node is allowed as a child of its new parent.
   if (!IsAllowedAsChild(newContent, this, aReplace, aRefChild)) {
     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
   }
 
-  nsresult res;
-
   // If we're replacing
   if (aReplace) {
-    res = RemoveChildAt(insPos, true);
-    NS_ENSURE_SUCCESS(res, res);
+    RemoveChildAt(insPos, true);
   }
 
   if (newContent->IsRootOfAnonymousSubtree()) {
     // This is anonymous content.  Don't allow its insertion
     // anywhere, since it might have UnbindFromTree calls coming
     // its way.
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
@@ -4293,26 +4287,26 @@ nsINode::ReplaceOrInsertBefore(bool aRep
   if (oldParent) {
     PRInt32 removeIndex = oldParent->IndexOf(newContent);
     if (removeIndex < 0) {
       // newContent is anonymous.  We can't deal with this, so just bail
       NS_ERROR("How come our flags didn't catch this?");
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
 
-    res = oldParent->RemoveChildAt(removeIndex, true);
-    NS_ENSURE_SUCCESS(res, res);
+    oldParent->RemoveChildAt(removeIndex, true);
 
     // Adjust insert index if the node we ripped out was a sibling
     // of the node we're inserting before
     if (oldParent == this && removeIndex < insPos) {
       --insPos;
     }
   }
 
+  nsresult res = NS_OK;
   // Move new child over to our document if needed. Do this after removing
   // it from its parent so that AdoptNode doesn't fire DOMNodeRemoved
   // DocumentType nodes are the only nodes that can have a null
   // ownerDocument according to the DOM spec, and we need to allow
   // inserting them w/o calling AdoptNode().
   if (!HasSameOwnerDoc(newContent)) {
     res = AdoptNodeIntoOwnerDoc(this, aNewChild);
     NS_ENSURE_SUCCESS(res, res);
@@ -5616,17 +5610,17 @@ nsGenericElement::GetAttrCount() const
 
 const nsTextFragment*
 nsGenericElement::GetText()
 {
   return nsnull;
 }
 
 PRUint32
-nsGenericElement::TextLength()
+nsGenericElement::TextLength() const
 {
   // We can remove this assertion if it turns out to be useful to be able
   // to depend on this returning 0
   NS_NOTREACHED("called nsGenericElement::TextLength");
 
   return 0;
 }
 
@@ -6411,16 +6405,35 @@ nsINode::Contains(const nsINode* aOther)
 nsresult
 nsINode::Contains(nsIDOMNode* aOther, bool* aReturn)
 {
   nsCOMPtr<nsINode> node = do_QueryInterface(aOther);
   *aReturn = Contains(node);
   return NS_OK;
 }
 
+PRUint32
+nsINode::Length() const
+{
+  switch (NodeType()) {
+  case nsIDOMNode::DOCUMENT_TYPE_NODE:
+    return 0;
+
+  case nsIDOMNode::TEXT_NODE:
+  case nsIDOMNode::CDATA_SECTION_NODE:
+  case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
+  case nsIDOMNode::COMMENT_NODE:
+    MOZ_ASSERT(IsNodeOfType(eCONTENT));
+    return static_cast<const nsIContent*>(this)->TextLength();
+
+  default:
+    return GetChildCount();
+  }
+}
+
 nsresult nsGenericElement::MozRequestFullScreen()
 {
   // Only grant full-screen requests if this is called from inside a trusted
   // event handler (i.e. inside an event handler for a user initiated event).
   // This stops the full-screen from being abused similar to the popups of old,
   // and it also makes it harder for bad guys' script to go full-screen and
   // spoof the browser chrome/window and phish logins etc.
   if (!nsContentUtils::IsRequestFullScreenAllowed()) {
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -258,17 +258,17 @@ public:
 
   // nsINode interface methods
   virtual PRUint32 GetChildCount() const;
   virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
   virtual nsIContent * const * GetChildArray(PRUint32* aChildCount) const;
   virtual PRInt32 IndexOf(nsINode* aPossibleChild) const;
   virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                                  bool aNotify);
-  virtual nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
+  virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify);
   NS_IMETHOD GetTextContent(nsAString &aTextContent);
   NS_IMETHOD SetTextContent(const nsAString& aTextContent);
 
   // nsIContent interface methods
   virtual void UpdateEditableState(bool aNotify);
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
@@ -322,17 +322,17 @@ public:
                                   nsIAtom* aName,
                                   AttrValuesArray* aValues,
                                   nsCaseTreatment aCaseSensitive) const;
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify);
   virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const;
   virtual PRUint32 GetAttrCount() const;
   virtual const nsTextFragment *GetText();
-  virtual PRUint32 TextLength();
+  virtual PRUint32 TextLength() const;
   virtual nsresult SetText(const PRUnichar* aBuffer, PRUint32 aLength,
                            bool aNotify);
   // Need to implement this here too to avoid hiding.
   nsresult SetText(const nsAString& aStr, bool aNotify)
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
   virtual nsresult AppendText(const PRUnichar* aBuffer, PRUint32 aLength,
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1860,16 +1860,57 @@ GK_ATOM(lockedStyleStates, "lockedStyleS
 
 // Languages for lang-specific transforms
 GK_ATOM(Japanese, "ja")
 GK_ATOM(Chinese, "zh-CN")
 GK_ATOM(Taiwanese, "zh-TW")
 GK_ATOM(HongKongChinese, "zh-HK")
 GK_ATOM(Unicode, "x-unicode")
 
+// language codes specifically referenced in the gfx code
+GK_ATOM(ko, "ko")
+GK_ATOM(zh_cn, "zh-cn")
+GK_ATOM(zh_hk, "zh-hk")
+GK_ATOM(zh_tw, "zh-tw")
+
+// additional codes used in nsUnicodeRange.cpp
+GK_ATOM(x_cyrillic, "x-cyrillic")
+GK_ATOM(he, "he")
+GK_ATOM(ar, "ar")
+GK_ATOM(x_baltic, "x-baltic")
+GK_ATOM(x_devanagari, "x-devanagari")
+GK_ATOM(x_tamil, "x-tamil")
+GK_ATOM(x_armn, "x-armn")
+GK_ATOM(x_beng, "x-beng")
+GK_ATOM(x_cans, "x-cans")
+GK_ATOM(x_ethi, "x-ethi")
+GK_ATOM(x_geor, "x-geor")
+GK_ATOM(x_gujr, "x-gujr")
+GK_ATOM(x_guru, "x-guru")
+GK_ATOM(x_khmr, "x-khmr")
+GK_ATOM(x_knda, "x-knda")
+GK_ATOM(x_mlym, "x-mlym")
+GK_ATOM(x_orya, "x-orya")
+GK_ATOM(x_sinh, "x-sinh")
+GK_ATOM(x_telu, "x-telu")
+GK_ATOM(x_tibt, "x-tibt")
+
+// used in gfxGDIFontList.h
+GK_ATOM(ko_xxx, "ko-xxx")
+GK_ATOM(x_central_euro, "x-central-euro")
+GK_ATOM(x_symbol, "x-symbol")
+
+// referenced in all.js
+GK_ATOM(x_user_def, "x-user-def")
+
+// additional languages that use Turkish-style case transformation
+GK_ATOM(az, "az")
+GK_ATOM(ba, "ba")
+GK_ATOM(crh, "crh")
+
 // Names for editor transactions
 GK_ATOM(TypingTxnName, "Typing")
 GK_ATOM(IMETxnName, "IME")
 GK_ATOM(DeleteTxnName, "Deleting")
 
 // IPC stuff
 GK_ATOM(Remote, "remote")
 GK_ATOM(RemoteId, "_remote_id")
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -617,26 +617,16 @@ nsRange::ParentChainChanged(nsIContent *
   NS_ASSERTION(newRoot, "No valid boundary or root found!");
   NS_ASSERTION(newRoot == IsValidBoundary(mEndParent),
                "Start parent and end parent give different root!");
   // This is safe without holding a strong ref to self as long as the change
   // of mRoot is the last thing in DoSetRange.
   DoSetRange(mStartParent, mStartOffset, mEndParent, mEndOffset, newRoot);
 }
 
-// Private helper routine: get the length of aNode
-static PRUint32 GetNodeLength(nsINode *aNode)
-{
-  if(aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
-    return static_cast<nsIContent*>(aNode)->TextLength();
-  }
-
-  return aNode->GetChildCount();
-}
-
 /******************************************************
  * Utilities for comparing points: API from nsIDOMRange
  ******************************************************/
 NS_IMETHODIMP
 nsRange::IsPointInRange(nsIDOMNode* aParent, PRInt32 aOffset, bool* aResult)
 {
   PRInt16 compareResult = 0;
   nsresult rv = ComparePoint(aParent, aOffset, &compareResult);
@@ -669,17 +659,17 @@ nsRange::ComparePoint(nsIDOMNode* aParen
   if (!nsContentUtils::ContentIsDescendantOf(parent, mRoot)) {
     return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
   }
   
   if (parent->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
     return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
   }
 
-  if (aOffset < 0 || aOffset > GetNodeLength(parent)) {
+  if (aOffset < 0 || aOffset > parent->Length()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
   
   PRInt32 cmp;
   if ((cmp = nsContentUtils::ComparePoints(parent, aOffset,
                                            mStartParent, mStartOffset)) <= 0) {
     
     *aResult = cmp;
@@ -933,19 +923,19 @@ nsRange::SetStart(nsIDOMNode* aParent, P
 }
 
 /* virtual */ nsresult
 nsRange::SetStart(nsINode* aParent, PRInt32 aOffset)
 {
   nsINode* newRoot = IsValidBoundary(aParent);
   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
 
-  PRInt32 len = GetNodeLength(aParent);
-  if (aOffset < 0 || aOffset > len)
+  if (aOffset < 0 || aOffset > aParent->Length()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  }
 
   // Collapse if not positioned yet, if positioned in another doc or
   // if the new start is after end.
   if (!mIsPositioned || newRoot != mRoot ||
       nsContentUtils::ComparePoints(aParent, aOffset,
                                     mEndParent, mEndOffset) == 1) {
     DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
 
@@ -997,18 +987,17 @@ nsRange::SetEnd(nsIDOMNode* aParent, PRI
 
 
 /* virtual */ nsresult
 nsRange::SetEnd(nsINode* aParent, PRInt32 aOffset)
 {
   nsINode* newRoot = IsValidBoundary(aParent);
   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
 
-  PRInt32 len = GetNodeLength(aParent);
-  if (aOffset < 0 || aOffset > len) {
+  if (aOffset < 0 || aOffset > aParent->Length()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   // Collapse if not positioned yet, if positioned in another doc or
   // if the new end is before start.
   if (!mIsPositioned || newRoot != mRoot ||
       nsContentUtils::ComparePoints(mStartParent, mStartOffset,
                                     aParent, aOffset) == 1) {
@@ -1095,17 +1084,17 @@ nsRange::SelectNodeContents(nsIDOMNode* 
 {
   VALIDATE_ACCESS(aN);
 
   nsCOMPtr<nsINode> node = do_QueryInterface(aN);
   nsINode* newRoot = IsValidBoundary(node);
   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
   
   AutoInvalidateSelection atEndOfBlock(this);
-  DoSetRange(node, 0, node, GetNodeLength(node), newRoot);
+  DoSetRange(node, 0, node, node->Length(), newRoot);
   
   return NS_OK;
 }
 
 // The Subtree Content Iterator only returns subtrees that are
 // completely within a given range. It doesn't return a CharacterData
 // node that contains either the start or end point of the range.,
 // nor does it return element nodes when nothing in the element is selected.
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -913,17 +913,18 @@ nsScriptLoader::EvaluateScript(nsScriptL
   nsCAutoString url;
   nsContentUtils::GetWrapperSafeScriptFilename(mDocument, aRequest->mURI, url);
 
   bool isUndefined;
   rv = context->EvaluateString(aScript, globalObject->GetGlobalJSObject(),
                                mDocument->NodePrincipal(),
                                aRequest->mOriginPrincipal,
                                url.get(), aRequest->mLineNo,
-                               aRequest->mJSVersion, nsnull, &isUndefined);
+                               JSVersion(aRequest->mJSVersion), nsnull,
+                               &isUndefined);
 
   // Put the old script back in case it wants to do anything else.
   mCurrentScript = oldCurrent;
 
   JSContext *cx = nsnull; // Initialize this to keep GCC happy.
   if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
     cx = context->GetNativeContext();
     ::JS_BeginRequest(cx);
--- a/content/html/content/src/nsHTMLFieldSetElement.cpp
+++ b/content/html/content/src/nsHTMLFieldSetElement.cpp
@@ -215,17 +215,17 @@ nsHTMLFieldSetElement::InsertChildAt(nsI
 
   if (firstLegendHasChanged) {
     NotifyElementsForFirstLegendChange(aNotify);
   }
 
   return rv;
 }
 
-nsresult
+void
 nsHTMLFieldSetElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
   bool firstLegendHasChanged = false;
 
   if (mFirstLegend && (GetChildAt(aIndex) == mFirstLegend)) {
     // If we are removing the first legend we have to found another one.
     nsIContent* child = mFirstLegend->GetNextSibling();
     mFirstLegend = nsnull;
@@ -234,24 +234,21 @@ nsHTMLFieldSetElement::RemoveChildAt(PRU
     for (; child; child = child->GetNextSibling()) {
       if (child->IsHTML(nsGkAtoms::legend)) {
         mFirstLegend = child;
         break;
       }
     }
   }
 
-  nsresult rv = nsGenericHTMLFormElement::RemoveChildAt(aIndex, aNotify);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsGenericHTMLFormElement::RemoveChildAt(aIndex, aNotify);
 
   if (firstLegendHasChanged) {
     NotifyElementsForFirstLegendChange(aNotify);
   }
-
-  return rv;
 }
 
 void
 nsHTMLFieldSetElement::NotifyElementsForFirstLegendChange(bool aNotify)
 {
   /**
    * NOTE: this could be optimized if only call when the fieldset is currently
    * disabled.
--- a/content/html/content/src/nsHTMLFieldSetElement.h
+++ b/content/html/content/src/nsHTMLFieldSetElement.h
@@ -79,17 +79,17 @@ public:
 
   // nsIContent
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify);
 
   virtual nsresult InsertChildAt(nsIContent* aChild, PRUint32 aIndex,
                                      bool aNotify);
-  virtual nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
+  virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify);
 
   // nsIFormControl
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_FIELDSET; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsXPCClassInfo* GetClassInfo();
 
--- a/content/html/content/src/nsHTMLOptGroupElement.cpp
+++ b/content/html/content/src/nsHTMLOptGroupElement.cpp
@@ -67,20 +67,20 @@ public:
   NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
 
   // nsIDOMHTMLElement
   NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
 
   // nsIDOMHTMLOptGroupElement
   NS_DECL_NSIDOMHTMLOPTGROUPELEMENT
 
-  // nsGenericElement
+  // nsINode
   virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                                  bool aNotify);
-  virtual nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
+  virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify);
 
   // nsIContent
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   virtual nsEventStates IntrinsicState() const;
  
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
@@ -182,26 +182,22 @@ nsHTMLOptGroupElement::InsertChildAt(nsI
   nsSafeOptionListMutation safeMutation(GetSelect(), this, aKid, aIndex, aNotify);
   nsresult rv = nsGenericHTMLElement::InsertChildAt(aKid, aIndex, aNotify);
   if (NS_FAILED(rv)) {
     safeMutation.MutationFailed();
   }
   return rv;
 }
 
-nsresult
+void
 nsHTMLOptGroupElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
   nsSafeOptionListMutation safeMutation(GetSelect(), this, nsnull, aIndex,
                                         aNotify);
-  nsresult rv = nsGenericHTMLElement::RemoveChildAt(aIndex, aNotify);
-  if (NS_FAILED(rv)) {
-    safeMutation.MutationFailed();
-  }
-  return rv;
+  nsGenericHTMLElement::RemoveChildAt(aIndex, aNotify);
 }
 
 nsEventStates
 nsHTMLOptGroupElement::IntrinsicState() const
 {
   nsEventStates state = nsGenericHTMLElement::IntrinsicState();
 
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -225,25 +225,21 @@ nsHTMLSelectElement::InsertChildAt(nsICo
   nsSafeOptionListMutation safeMutation(this, this, aKid, aIndex, aNotify);
   nsresult rv = nsGenericHTMLFormElement::InsertChildAt(aKid, aIndex, aNotify);
   if (NS_FAILED(rv)) {
     safeMutation.MutationFailed();
   }
   return rv;
 }
 
-nsresult
+void
 nsHTMLSelectElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
   nsSafeOptionListMutation safeMutation(this, this, nsnull, aIndex, aNotify);
-  nsresult rv = nsGenericHTMLFormElement::RemoveChildAt(aIndex, aNotify);
-  if (NS_FAILED(rv)) {
-    safeMutation.MutationFailed();
-  }
-  return rv;
+  nsGenericHTMLFormElement::RemoveChildAt(aIndex, aNotify);
 }
 
 
 // SelectElement methods
 
 nsresult
 nsHTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions,
                                            PRInt32 aListIndex,
--- a/content/html/content/src/nsHTMLSelectElement.h
+++ b/content/html/content/src/nsHTMLSelectElement.h
@@ -291,17 +291,17 @@ public:
 
   // nsIContent
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
 
   virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex);
   virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                                  bool aNotify);
-  virtual nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
+  virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify);
 
   // Overriden nsIFormControl methods
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_SELECT; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   virtual bool RestoreState(nsPresState* aState);
 
--- a/content/svg/content/src/DOMSVGTests.cpp
+++ b/content/svg/content/src/DOMSVGTests.cpp
@@ -256,18 +256,18 @@ nsIAtom*
 DOMSVGTests::GetAttrName(PRUint8 aAttrEnum) const
 {
   return *sStringListNames[aAttrEnum];
 }
 
 void
 DOMSVGTests::GetAttrValue(PRUint8 aAttrEnum, nsAttrValue& aValue) const
 {
-  NS_ABORT_IF_FALSE(aAttrEnum >= 0 && aAttrEnum < ArrayLength(sStringListNames),
-                    "aAttrEnum out of range");
+  MOZ_ASSERT(aAttrEnum < ArrayLength(sStringListNames),
+             "aAttrEnum out of range");
   aValue.SetTo(mStringListAttributes[aAttrEnum], nsnull);
 }
 
 void
 DOMSVGTests::MaybeInvalidate()
 {
   nsCOMPtr<nsSVGElement> element = do_QueryInterface(this);
 
--- a/content/svg/content/src/nsSVGSwitchElement.cpp
+++ b/content/svg/content/src/nsSVGSwitchElement.cpp
@@ -121,24 +121,21 @@ nsSVGSwitchElement::InsertChildAt(nsICon
 {
   nsresult rv = nsSVGSwitchElementBase::InsertChildAt(aKid, aIndex, aNotify);
   if (NS_SUCCEEDED(rv)) {
     MaybeInvalidate();
   }
   return rv;
 }
 
-nsresult
+void
 nsSVGSwitchElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
-  nsresult rv = nsSVGSwitchElementBase::RemoveChildAt(aIndex, aNotify);
-  if (NS_SUCCEEDED(rv)) {
-    MaybeInvalidate();
-  }
-  return rv;
+  nsSVGSwitchElementBase::RemoveChildAt(aIndex, aNotify);
+  MaybeInvalidate();
 }
  
 //----------------------------------------------------------------------
 // nsIContent methods
 
 NS_IMETHODIMP_(bool)
 nsSVGSwitchElement::IsAttributeMapped(const nsIAtom* name) const
 {
--- a/content/svg/content/src/nsSVGSwitchElement.h
+++ b/content/svg/content/src/nsSVGSwitchElement.h
@@ -70,17 +70,17 @@ public:
   // xxx I wish we could use virtual inheritance
   NS_FORWARD_NSIDOMNODE(nsSVGSwitchElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGSwitchElementBase::)
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGSwitchElementBase::)
 
   // nsINode
   virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                                  bool aNotify);
-  virtual nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
+  virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify);
 
   // nsIContent
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   virtual nsXPCClassInfo* GetClassInfo();
 private:
--- a/content/xslt/src/xslt/txMozillaXMLOutput.cpp
+++ b/content/xslt/src/xslt/txMozillaXMLOutput.cpp
@@ -686,18 +686,17 @@ txMozillaXMLOutput::createTxWrapper()
             // The new documentElement should go after the document type.
             // This is needed for cases when there is no existing
             // documentElement in the document.
             rootLocation = NS_MAX(rootLocation, j + 1);
 #endif
             ++j;
         }
         else {
-            rv = mDocument->RemoveChildAt(j, true);
-            NS_ENSURE_SUCCESS(rv, rv);
+            mDocument->RemoveChildAt(j, true);
 
             rv = wrapper->AppendChildTo(childContent, true);
             NS_ENSURE_SUCCESS(rv, rv);
             break;
         }
     }
 
     if (!mCurrentNodeStack.AppendObject(wrapper)) {
--- a/content/xtf/src/nsXTFElementWrapper.cpp
+++ b/content/xtf/src/nsXTFElementWrapper.cpp
@@ -265,26 +265,24 @@ nsXTFElementWrapper::InsertChildAt(nsICo
     GetXTFElement()->WillInsertChild(domKid, aIndex);
   rv = nsXTFElementWrapperBase::InsertChildAt(aKid, aIndex, aNotify);
   if (mNotificationMask & nsIXTFElement::NOTIFY_CHILD_INSERTED)
     GetXTFElement()->ChildInserted(domKid, aIndex);
   
   return rv;
 }
 
-nsresult
+void
 nsXTFElementWrapper::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
-  nsresult rv;
   if (mNotificationMask & nsIXTFElement::NOTIFY_WILL_REMOVE_CHILD)
     GetXTFElement()->WillRemoveChild(aIndex);
-  rv = nsXTFElementWrapperBase::RemoveChildAt(aIndex, aNotify);
+  nsXTFElementWrapperBase::RemoveChildAt(aIndex, aNotify);
   if (mNotificationMask & nsIXTFElement::NOTIFY_CHILD_REMOVED)
     GetXTFElement()->ChildRemoved(aIndex);
-  return rv;
 }
 
 nsIAtom *
 nsXTFElementWrapper::GetIDAttributeName() const
 {
   // XXX:
   return nsGkAtoms::id;
 }
--- a/content/xtf/src/nsXTFElementWrapper.h
+++ b/content/xtf/src/nsXTFElementWrapper.h
@@ -79,17 +79,17 @@ public:
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers);
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true);
   nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                          bool aNotify);
-  nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
+  void RemoveChildAt(PRUint32 aIndex, bool aNotify);
   nsIAtom *GetIDAttributeName() const;
   nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                    nsIAtom* aPrefix, const nsAString& aValue,
                    bool aNotify);
   bool GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, 
                  nsAString& aResult) const;
   bool HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const;
   virtual bool AttrValueIs(PRInt32 aNameSpaceID, nsIAtom* aName,
--- a/content/xul/content/src/nsXULContextMenuBuilder.cpp
+++ b/content/xul/content/src/nsXULContextMenuBuilder.cpp
@@ -184,17 +184,18 @@ nsXULContextMenuBuilder::UndoAddSeparato
   }
 
   PRUint32 count = mCurrentNode->GetChildCount();
   if (!count ||
       mCurrentNode->GetChildAt(count - 1)->Tag() != nsGkAtoms::menuseparator) {
     return NS_OK;
   }
 
-  return mCurrentNode->RemoveChildAt(count - 1, false);
+  mCurrentNode->RemoveChildAt(count - 1, false);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULContextMenuBuilder::CloseContainer()
 {
   if (!mFragment) {
     return NS_ERROR_NOT_INITIALIZED;
   }
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -803,22 +803,21 @@ nsScriptEventHandlerOwnerTearoff::Compil
     nsXULPrototypeAttribute *attr =
         mElement->FindPrototypeAttribute(kNameSpaceID_None, aName);
     if (attr) {
         XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheFills);
         // take a copy of the event handler, and tell the language about it.
         if (aHandler) {
             NS_ASSERTION(!attr->mEventHandler, "Leaking handler.");
 
-            rv = nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(),
-                                                  elem,
-                                                  &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode),
-                                                  aHandler.get(),
-                                                  elem->mHoldsScriptObject);
-            if (NS_FAILED(rv)) return rv;
+            if (!elem->mHoldsScriptObject) {
+                rv = nsContentUtils::HoldJSObjects(
+                    elem, &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode));
+                NS_ENSURE_SUCCESS(rv, rv);
+            }
 
             elem->mHoldsScriptObject = true;
         }
         attr->mEventHandler = aHandler.get();
     }
 
     return NS_OK;
 }
@@ -920,23 +919,22 @@ nsXULElement::UnbindFromTree(bool aDeep,
             slots->mFrameLoader->Destroy();
             slots->mFrameLoader = nsnull;
         }
     }
 
     nsStyledElement::UnbindFromTree(aDeep, aNullParent);
 }
 
-nsresult
+void
 nsXULElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
-    nsresult rv;
     nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
     if (!oldKid) {
-      return NS_OK;
+      return;
     }
 
     // On the removal of a <treeitem>, <treechildren>, or <treecell> element,
     // the possibility exists that some of the items in the removed subtree
     // are selected (and therefore need to be deselected). We need to account for this.
     nsCOMPtr<nsIDOMXULMultiSelectControlElement> controlElement;
     nsCOMPtr<nsIListBoxObject> listBox;
     bool fireSelectionHandler = false;
@@ -949,17 +947,17 @@ nsXULElement::RemoveChildAt(PRUint32 aIn
       // This is the nasty case. We have (potentially) a slew of selected items
       // and cells going away.
       // First, retrieve the tree.
       // Check first whether this element IS the tree
       controlElement = do_QueryObject(this);
 
       // If it's not, look at our parent
       if (!controlElement)
-        rv = GetParentTree(getter_AddRefs(controlElement));
+        GetParentTree(getter_AddRefs(controlElement));
 
       nsCOMPtr<nsIDOMElement> oldKidElem = do_QueryInterface(oldKid);
       if (controlElement && oldKidElem) {
         // Iterate over all of the items and find out if they are contained inside
         // the removed subtree.
         PRInt32 length;
         controlElement->GetSelectedCount(&length);
         for (PRInt32 i = 0; i < length; i++) {
@@ -989,17 +987,17 @@ nsXULElement::RemoveChildAt(PRUint32 aIn
 
             // If any of this fails, we'll just set the current item to null
             if (newCurrentIndex == -1)
               newCurrentIndex = -2;
         }
       }
     }
 
-    rv = nsStyledElement::RemoveChildAt(aIndex, aNotify);
+    nsStyledElement::RemoveChildAt(aIndex, aNotify);
     
     if (newCurrentIndex == -2)
         controlElement->SetCurrentItem(nsnull);
     else if (newCurrentIndex > -1) {
         // Make sure the index is still valid
         PRInt32 treeRows;
         listBox->GetRowCount(&treeRows);
         if (treeRows > 0) {
@@ -1017,18 +1015,16 @@ nsXULElement::RemoveChildAt(PRUint32 aIn
     nsIDocument* doc;
     if (fireSelectionHandler && (doc = GetCurrentDoc())) {
       nsContentUtils::DispatchTrustedEvent(doc,
                                            static_cast<nsIContent*>(this),
                                            NS_LITERAL_STRING("select"),
                                            false,
                                            true);
     }
-
-    return rv;
 }
 
 void
 nsXULElement::UnregisterAccessKey(const nsAString& aOldValue)
 {
     // If someone changes the accesskey, unregister the old one
     //
     nsIDocument* doc = GetCurrentDoc();
@@ -2900,18 +2896,17 @@ nsXULPrototypeElement::SetAttrAt(PRUint3
 
     return NS_OK;
 }
 
 void
 nsXULPrototypeElement::Unlink()
 {
     if (mHoldsScriptObject) {
-        nsContentUtils::DropScriptObjects(mScriptTypeID, this,
-                                          &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode));
+        nsContentUtils::DropJSObjects(this);
         mHoldsScriptObject = false;
     }
     mNumAttributes = 0;
     delete[] mAttributes;
     mAttributes = nsnull;
 }
 
 //----------------------------------------------------------------------
@@ -3180,36 +3175,32 @@ nsXULPrototypeScript::Compile(const PRUn
     Set(newScriptObject);
     return rv;
 }
 
 void
 nsXULPrototypeScript::UnlinkJSObjects()
 {
     if (mScriptObject.mObject) {
-        nsContentUtils::DropScriptObjects(mScriptObject.mLangID, this,
-                                          &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode));
+        nsContentUtils::DropJSObjects(this);
         mScriptObject.mObject = nsnull;
     }
 }
 
 void
 nsXULPrototypeScript::Set(JSScript* aObject)
 {
     NS_ASSERTION(!mScriptObject.mObject, "Leaking script object.");
     if (!aObject) {
         mScriptObject.mObject = nsnull;
-
         return;
     }
 
-    nsresult rv = nsContentUtils::HoldScriptObject(mScriptObject.mLangID,
-                                                   this,
-                                                   &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode),
-                                                   aObject, false);
+    nsresult rv = nsContentUtils::HoldJSObjects(
+        this, &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode));
     if (NS_SUCCEEDED(rv)) {
         mScriptObject.mObject = aObject;
     }
 }
 
 //----------------------------------------------------------------------
 //
 // nsXULPrototypeText
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -477,17 +477,17 @@ public:
     // nsINode
     virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
     // nsIContent
     virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                 nsIContent* aBindingParent,
                                 bool aCompileEventHandlers);
     virtual void UnbindFromTree(bool aDeep, bool aNullParent);
-    virtual nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
+    virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify);
     virtual bool GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                            nsAString& aResult) const;
     virtual bool HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const;
     virtual bool AttrValueIs(PRInt32 aNameSpaceID, nsIAtom* aName,
                                const nsAString& aValue,
                                nsCaseTreatment aCaseSensitive) const;
     virtual bool AttrValueIs(PRInt32 aNameSpaceID, nsIAtom* aName,
                                nsIAtom* aValue,
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -4110,25 +4110,23 @@ nsXULDocument::OverlayForwardReference::
             nsIAtom *parentID = elementParent->GetID();
             if (parentID &&
                 aTargetNode->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id,
                                          nsDependentAtomString(parentID),
                                          eCaseMatters)) {
                 // The element matches. "Go Deep!"
                 rv = Merge(elementInDocument, currContent, aNotify);
                 if (NS_FAILED(rv)) return rv;
-                rv = aOverlayNode->RemoveChildAt(0, false);
-                if (NS_FAILED(rv)) return rv;
+                aOverlayNode->RemoveChildAt(0, false);
 
                 continue;
             }
         }
 
-        rv = aOverlayNode->RemoveChildAt(0, false);
-        if (NS_FAILED(rv)) return rv;
+        aOverlayNode->RemoveChildAt(0, false);
 
         rv = InsertElement(aTargetNode, currContent, aNotify);
         if (NS_FAILED(rv)) return rv;
     }
 
     return NS_OK;
 }
 
@@ -4508,17 +4506,18 @@ nsXULDocument::InsertElement(nsIContent*
     return NS_OK;
 }
 
 nsresult
 nsXULDocument::RemoveElement(nsIContent* aParent, nsIContent* aChild)
 {
     PRInt32 nodeOffset = aParent->IndexOf(aChild);
 
-    return aParent->RemoveChildAt(nodeOffset, true);
+    aParent->RemoveChildAt(nodeOffset, true);
+    return NS_OK;
 }
 
 //----------------------------------------------------------------------
 //
 // CachedChromeStreamListener
 //
 
 nsXULDocument::CachedChromeStreamListener::CachedChromeStreamListener(nsXULDocument* aDocument, bool aProtoLoaded)
--- a/content/xul/templates/src/nsXULContentBuilder.cpp
+++ b/content/xul/templates/src/nsXULContentBuilder.cpp
@@ -951,18 +951,17 @@ nsXULContentBuilder::RemoveMember(nsICon
         PRInt32 pos = parent->IndexOf(aContent);
 
         NS_ASSERTION(pos >= 0, "parent doesn't think this child has an index");
         if (pos < 0) return NS_OK;
 
         // Note: RemoveChildAt sets |child|'s document to null so that
         // it'll get knocked out of the XUL doc's resource-to-element
         // map.
-        nsresult rv = parent->RemoveChildAt(pos, true);
-        if (NS_FAILED(rv)) return rv;
+        parent->RemoveChildAt(pos, true);
     }
 
     // Remove from the content support map.
     mContentSupportMap.Remove(aContent);
 
     // Remove from the template map
     mTemplateMap.Remove(aContent);
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -9282,18 +9282,17 @@ nsGlobalWindow::RunTimeout(nsTimeout *aT
       PRUint32 lineNo = 0;
       handler->GetLocation(&filename, &lineNo);
 
       NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo);
 
       bool is_undefined;
       scx->EvaluateString(nsDependentString(script), FastGetGlobalJSObject(),
                           timeout->mPrincipal, timeout->mPrincipal,
-                          filename, lineNo,
-                          handler->GetScriptVersion(), nsnull,
+                          filename, lineNo, JSVERSION_DEFAULT, nsnull,
                           &is_undefined);
     } else {
       nsCOMPtr<nsIVariant> dummy;
       nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
       scx->CallEventHandler(me, FastGetGlobalJSObject(),
                             scriptObject, handler->GetArgv(),
                             // XXXmarkh - consider allowing CallEventHandler to
                             // accept nsnull?
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -119,17 +119,17 @@ public:
    *
    **/
   virtual nsresult EvaluateString(const nsAString& aScript,
                                   JSObject* aScopeObject,
                                   nsIPrincipal *aPrincipal,
                                   nsIPrincipal *aOriginPrincipal,
                                   const char *aURL,
                                   PRUint32 aLineNo,
-                                  PRUint32 aVersion,
+                                  JSVersion aVersion,
                                   nsAString *aRetValue,
                                   bool* aIsUndefined) = 0;
 
   virtual nsresult EvaluateStringWithValue(const nsAString& aScript,
                                            JSObject* aScopeObject,
                                            nsIPrincipal *aPrincipal,
                                            const char *aURL,
                                            PRUint32 aLineNo,
--- a/dom/base/nsIScriptTimeoutHandler.h
+++ b/dom/base/nsIScriptTimeoutHandler.h
@@ -37,19 +37,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 #ifndef nsIScriptTimeoutHandler_h___
 #define nsIScriptTimeoutHandler_h___
 
 class nsIArray;
 
 #define NS_ISCRIPTTIMEOUTHANDLER_IID \
-{ /* {17a9ce1a-d73b-45d1-8145-a0ae57bcc76e} */ \
-  0x17a9ce1a, 0xd73b, 0x45d1, \
- { 0x81, 0x45, 0xa0, 0xae, 0x57, 0xbc, 0xc7, 0x6e } }
+{ 0xd60ec934, 0x0c75, 0x4777, \
+  { 0xba, 0x41, 0xb8, 0x2f, 0x37, 0xc9, 0x13, 0x56 } }
 
 /**
  * Abstraction of the script objects etc required to do timeouts in a
  * language agnostic way.
  */
 
 class nsIScriptTimeoutHandler : public nsISupports
 {
@@ -70,17 +69,14 @@ public:
   // Get the location of the script.
   // Note: The memory pointed to by aFileName is owned by the
   // nsIScriptTimeoutHandler and should not be freed by the caller.
   virtual void GetLocation(const char **aFileName, PRUint32 *aLineNo) = 0;
 
   // If a script object, get the argv suitable for passing back to the
   // script context.
   virtual nsIArray *GetArgv() = 0;
-
-  // Get the language version for this timeout.
-  virtual PRUint32 GetScriptVersion() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptTimeoutHandler,
                               NS_ISCRIPTTIMEOUTHANDLER_IID)
 
 #endif // nsIScriptTimeoutHandler_h___
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1353,17 +1353,17 @@ nsJSContext::GetObjectPrincipal()
 
 nsresult
 nsJSContext::EvaluateString(const nsAString& aScript,
                             JSObject* aScopeObject,
                             nsIPrincipal *aPrincipal,
                             nsIPrincipal *aOriginPrincipal,
                             const char *aURL,
                             PRUint32 aLineNo,
-                            PRUint32 aVersion,
+                            JSVersion aVersion,
                             nsAString *aRetValue,
                             bool* aIsUndefined)
 {
   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME,
                            __LINE__, aURL, aLineNo);
 
   SAMPLE_LABEL("JS", "EvaluateString");
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -83,17 +83,17 @@ public:
   }
 
   virtual nsresult EvaluateString(const nsAString& aScript,
                                   JSObject* aScopeObject,
                                   nsIPrincipal *principal,
                                   nsIPrincipal *originPrincipal,
                                   const char *aURL,
                                   PRUint32 aLineNo,
-                                  PRUint32 aVersion,
+                                  JSVersion aVersion,
                                   nsAString *aRetValue,
                                   bool* aIsUndefined);
   virtual nsresult EvaluateStringWithValue(const nsAString& aScript,
                                            JSObject* aScopeObject,
                                            nsIPrincipal* aPrincipal,
                                            const char* aURL,
                                            PRUint32 aLineNo,
                                            PRUint32 aVersion,
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -74,19 +74,16 @@ public:
   virtual void GetLocation(const char **aFileName, PRUint32 *aLineNo) {
     *aFileName = mFileName.get();
     *aLineNo = mLineNo;
   }
 
   virtual PRUint32 GetScriptTypeID() {
         return nsIProgrammingLanguage::JAVASCRIPT;
   }
-  virtual PRUint32 GetScriptVersion() {
-        return mVersion;
-  }
 
   virtual nsIArray *GetArgv() {
     return mArgv;
   }
 
   nsresult Init(nsGlobalWindow *aWindow, bool *aIsInterval,
                 PRInt32 *aInterval);
 
--- a/dom/interfaces/storage/nsIDOMStorage.idl
+++ b/dom/interfaces/storage/nsIDOMStorage.idl
@@ -59,18 +59,17 @@ interface nsIDOMStorage : nsISupports
    * The number of keys stored.
    */
   readonly attribute unsigned long length;
 
   /**
    * Retrieve the name of the key at a particular index.
    *
    * @param index index of the item to retrieve
-   * @returns the key at index
-   * @throws INDEX_SIZE_ERR if there is no key at that index
+   * @returns the key at index, null if there is no key at that index
    */
   DOMString key(in unsigned long index);
 
   /**
    * Retrieve an item with a given key
    *
    * @param key key to retrieve
    * @returns found data or empty string if the key was not found
--- a/dom/src/events/nsJSEventListener.cpp
+++ b/dom/src/events/nsJSEventListener.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -81,43 +81,30 @@ nsJSEventListener::nsJSEventListener(nsI
                                      JSObject *aHandler)
   : nsIJSEventListener(aContext, aScopeObject, aTarget, aHandler),
     mEventName(aType)
 {
   // aScopeObject is the inner window's JS object, which we need to lock
   // until we are done with it.
   NS_ASSERTION(aScopeObject && aContext,
                "EventListener with no context or scope?");
-  nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(), this,
-                                   &NS_CYCLE_COLLECTION_NAME(nsJSEventListener),
-                                   aScopeObject, false);
-  if (aHandler) {
-    nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(), this,
-                                     &NS_CYCLE_COLLECTION_NAME(nsJSEventListener),
-                                     aHandler, true);
-  }
+  NS_HOLD_JS_OBJECTS(this, nsJSEventListener);
 }
 
 nsJSEventListener::~nsJSEventListener() 
 {
-  if (mContext)
-    nsContentUtils::DropScriptObjects(mContext->GetScriptTypeID(), this,
-                                      &NS_CYCLE_COLLECTION_NAME(nsJSEventListener));
+  if (mContext) {
+    NS_DROP_JS_OBJECTS(this, nsJSEventListener);
+  }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSEventListener)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSEventListener)
   if (tmp->mContext) {
-    if (tmp->mContext->GetScriptTypeID() == nsIProgrammingLanguage::JAVASCRIPT) {
-      NS_DROP_JS_OBJECTS(tmp, nsJSEventListener);
-    }
-    else {
-      nsContentUtils::DropScriptObjects(tmp->mContext->GetScriptTypeID(), tmp,
-                                  &NS_CYCLE_COLLECTION_NAME(nsJSEventListener));
-    }
+    NS_DROP_JS_OBJECTS(tmp, nsJSEventListener);
     tmp->mScopeObject = nsnull;
     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSEventListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -358,17 +358,17 @@ nsresult nsJSThunk::EvaluateScript(nsICh
         // No need to use the sandbox, evaluate the script directly in
         // the given scope.
         rv = scriptContext->EvaluateString(NS_ConvertUTF8toUTF16(script),
                                            globalJSObject, // obj
                                            principal,
                                            principal,
                                            mURL.get(),     // url
                                            1,              // line no
-                                           nsnull,
+                                           JSVERSION_DEFAULT,
                                            &result,
                                            &isUndefined);
 
         // If there's an error on cx as a result of that call, report
         // it now -- either we're just running under the event loop,
         // so we shouldn't propagate JS exceptions out of here, or we
         // can't be sure that our caller is JS (and if it's not we'll
         // lose the error), or it might be JS that then proceeds to
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -1126,35 +1126,32 @@ IndexFinder(nsSessionStorageEntry* aEntr
   ++data->mIndex;
 
   return PL_DHASH_NEXT;
 }
 
 nsresult
 DOMStorageImpl::GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey)
 {
-  // XXXjst: This is as retarded as the DOM spec is, takes an unsigned
-  // int, but the spec talks about what to do if a negative value is
-  // passed in.
-
   // XXX: This does a linear search for the key at index, which would
   // suck if there's a large numer of indexes. Do we care? If so,
   // maybe we need to have a lazily populated key array here or
   // something?
 
   if (UseDB()) {
     CacheKeysFromDB();
   }
 
   IndexFinderData data(aCallerSecure, aIndex);
   mItems.EnumerateEntries(IndexFinder, &data);
 
   if (!data.mItem) {
-    // aIndex was larger than the number of accessible keys. Throw.
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+    // aIndex was larger than the number of accessible keys. Return null.
+    aKey.SetIsVoid(true);
+    return NS_OK;
   }
 
   aKey = data.mItem->GetKey();
   return NS_OK;
 }
 
 // The behaviour of this function must be kept in sync with StorageChild::GetValue.
 // See the explanatory comment there for more details.
--- a/dom/tests/mochitest/Makefile.in
+++ b/dom/tests/mochitest/Makefile.in
@@ -52,16 +52,17 @@ DIRS	+= \
 	chrome \
 	general \
 	whatwg \
 	geolocation \
 	localstorage \
 	orientation \
 	sessionstorage \
 	storageevent \
+	w3c \
 	browser-frame \
 	$(NULL)
 
 #needs IPC support, also tests do not run successfully in Firefox for now
 #ifneq (mobile,$(MOZ_BUILD_APP))
 #DIRS	+= notification
 #endif
 
--- a/dom/tests/mochitest/localstorage/test_localStorageBase.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBase.html
@@ -2,38 +2,23 @@
 <head>
 <title>localStorage basic test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-var INDEX_SIZE_ERR = 1;
-
-function checkException(func, exc)
-{
-  var exceptionThrew = false;
-  try {
-    func();
-  }
-  catch (ex) {
-    exceptionThrew = true;
-    is(ex.code, exc, "Expected "+exc+" exception");
-  }
-  ok(exceptionThrew, "Exception "+exc+" threw");
-}
-
 function startTest()
 {
   // Initially check the localStorage is empty
   is(localStorage.length, 0, "The storage is empty [1]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(localStorage["nonexisting"], null, "Nonexisting item is null (array access)");
   is(localStorage.nonexisting, null, "Nonexisting item is null (property access)");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
 
   is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
   is(typeof localStorage["nonexisting"], "object", "['nonexisting'] is object");
   is(typeof localStorage.nonexisting, "object", "nonexisting is object");
@@ -57,33 +42,33 @@ function startTest()
   is(typeof localStorage.getItem("empty"), "object", "getItem('empty') is object");
   is(typeof localStorage["empty"], "object", "['empty'] is object");
   is(typeof localStorage.empty, "object", "empty is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
 
   // check all access method give the correct result
   // and are of the correct type
   is(localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
   is(localStorage["key1"], "value1", "['key1'] == value1");
   is(localStorage.key1, "value1", "key1 == value1");
 
   is(typeof localStorage.getItem("key1"), "string", "getItem('key1') is string");
   is(typeof localStorage["key1"], "string", "['key1'] is string");
   is(typeof localStorage.key1, "string", "key1 is string");
 
   // remove the previously added key and check the storage is empty
   localStorage.removeItem("key1");
   is(localStorage.length, 0, "The storage is empty [2]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), null, "\'key1\' removed");
 
   is(typeof localStorage.getItem("key1"), "object", "getItem('key1') is object");
   is(typeof localStorage["key1"], "object", "['key1'] is object");
   is(typeof localStorage.key1, "object", "key1 is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
@@ -102,37 +87,37 @@ function startTest()
      (firstKey == 'key2' && secondKey == 'key1'),
      'key() API works.');
 
   // change the second key
   localStorage.setItem("key2", "value2-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1");
   is(localStorage.getItem("key2"), "value2-2");
 
   // change the first key
   localStorage.setItem("key1", "value1-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
   is(localStorage.getItem("key2"), "value2-2");
 
   // remove the second key
   localStorage.removeItem("key2");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
   
   // JS property test
   localStorage.testA = "valueA";
   is(localStorage.testA, "valueA");
   is(localStorage["testA"], "valueA");
   is(localStorage.getItem("testA"), "valueA");
   
@@ -161,19 +146,19 @@ function startTest()
   is(localStorage["testC"], "valueC2");
   is(localStorage.getItem("testC"), "valueC2");
   
   // Clear the storage
   localStorage.clear();
   is("testB" in localStorage, false, "Keys are not in the JS scope of the storage");
   is("testC" in localStorage, false, "Keys are not in the JS scope of the storage");
   is(localStorage.length, 0, "The storage is empty [3]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(localStorage.getItem("key1"), null, "key1 removed");
   is(localStorage.getItem("key2"), null, "key2 removed");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
   localStorage.removeItem("key1"); // Just check there is no exception
   localStorage.removeItem("key2"); // Just check there is no exception
 
   localStorage.clear();
--- a/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing.html
@@ -3,31 +3,16 @@
 <title>localStorage basic test, while in sesison only mode</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <script type="text/javascript" src="pbSwitch.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-var INDEX_SIZE_ERR = 1;
-
-function checkException(func, exc)
-{
-  var exceptionThrew = false;
-  try {
-    func();
-  }
-  catch (ex) {
-    exceptionThrew = true;
-    is(ex.code, exc, "Expected "+exc+" exception");
-  }
-  ok(exceptionThrew, "Exception "+exc+" threw");
-}
-
 function startTest()
 {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
   if (get_PBSvc())
     doTest();
   else
     ok(true, "No private browsing service, test could not be performed");
@@ -40,19 +25,19 @@ function doTest()
   localStorage.setItem("persistent", "persistent1");
 
   enterPrivateBrowsing();
 
   is(localStorage.getItem("persistent"), null, "previous values are inaccessible");
 
   // Initially check the localStorage is empty
   is(localStorage.length, 0, "The storage is empty [1]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(localStorage["nonexisting"], null, "Nonexisting item is null (array access)");
   is(localStorage.nonexisting, null, "Nonexisting item is null (property access)");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
 
   is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
   is(typeof localStorage["nonexisting"], "object", "['nonexisting'] is object");
   is(typeof localStorage.nonexisting, "object", "nonexisting is object");
@@ -76,33 +61,33 @@ function doTest()
   is(typeof localStorage.getItem("empty"), "object", "getItem('empty') is object");
   is(typeof localStorage["empty"], "object", "['empty'] is object");
   is(typeof localStorage.empty, "object", "empty is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
 
   // check all access method give the correct result
   // and are of the correct type
   is(localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
   is(localStorage["key1"], "value1", "['key1'] == value1");
   is(localStorage.key1, "value1", "key1 == value1");
 
   is(typeof localStorage.getItem("key1"), "string", "getItem('key1') is string");
   is(typeof localStorage["key1"], "string", "['key1'] is string");
   is(typeof localStorage.key1, "string", "key1 is string");
 
   // remove the previously added key and check the storage is empty
   localStorage.removeItem("key1");
   is(localStorage.length, 0, "The storage is empty [2]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), null, "\'key1\' removed");
 
   is(typeof localStorage.getItem("key1"), "object", "getItem('key1') is object");
   is(typeof localStorage["key1"], "object", "['key1'] is object");
   is(typeof localStorage.key1, "object", "key1 is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
@@ -121,37 +106,37 @@ function doTest()
      (firstKey == 'key2' && secondKey == 'key1'),
      'key() API works.');
 
   // change the second key
   localStorage.setItem("key2", "value2-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1");
   is(localStorage.getItem("key2"), "value2-2");
 
   // change the first key
   localStorage.setItem("key1", "value1-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
   is(localStorage.getItem("key2"), "value2-2");
 
   // remove the second key
   localStorage.removeItem("key2");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
 
   // JS property test
   localStorage.testA = "valueA";
   is(localStorage.testA, "valueA");
   is(localStorage["testA"], "valueA");
   is(localStorage.getItem("testA"), "valueA");
 
@@ -178,19 +163,19 @@ function doTest()
   localStorage.setItem("testC", "valueC2");
   is(localStorage.testC, "valueC2");
   is(localStorage["testC"], "valueC2");
   is(localStorage.getItem("testC"), "valueC2");
 
   // Clear the storage
   localStorage.clear();
   is(localStorage.length, 0, "The storage is empty [3]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(localStorage.getItem("key1"), null, "key1 removed");
   is(localStorage.getItem("key2"), null, "key2 removed");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
   localStorage.removeItem("key1"); // Just check there is no exception
   localStorage.removeItem("key2"); // Just check there is no exception
 
   localStorage.setItem("must disappear", "private browsing value");
--- a/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
@@ -2,48 +2,33 @@
 <head>
 <title>localStorage basic test, while in sesison only mode</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-var INDEX_SIZE_ERR = 1;
-
-function checkException(func, exc)
-{
-  var exceptionThrew = false;
-  try {
-    func();
-  }
-  catch (ex) {
-    exceptionThrew = true;
-    is(ex.code, exc, "Expected "+exc+" exception");
-  }
-  ok(exceptionThrew, "Exception "+exc+" threw");
-}
-
 function startTest()
 {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
   var io = Components.classes["@mozilla.org/network/io-service;1"]
     .getService(Components.interfaces.nsIIOService);
   var uri = io.newURI(window.location, "", null);
   var cp = Components.classes["@mozilla.org/cookie/permission;1"]
     .getService(Components.interfaces.nsICookiePermission);
   cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
 
 
   // Initially check the localStorage is empty
   is(localStorage.length, 0, "The storage is empty [1]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(localStorage["nonexisting"], null, "Nonexisting item is null (array access)");
   is(localStorage.nonexisting, null, "Nonexisting item is null (property access)");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
 
   is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
   is(typeof localStorage["nonexisting"], "object", "['nonexisting'] is object");
   is(typeof localStorage.nonexisting, "object", "nonexisting is object");
@@ -67,33 +52,33 @@ function startTest()
   is(typeof localStorage.getItem("empty"), "object", "getItem('empty') is object");
   is(typeof localStorage["empty"], "object", "['empty'] is object");
   is(typeof localStorage.empty, "object", "empty is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
 
   // check all access method give the correct result
   // and are of the correct type
   is(localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
   is(localStorage["key1"], "value1", "['key1'] == value1");
   is(localStorage.key1, "value1", "key1 == value1");
 
   is(typeof localStorage.getItem("key1"), "string", "getItem('key1') is string");
   is(typeof localStorage["key1"], "string", "['key1'] is string");
   is(typeof localStorage.key1, "string", "key1 is string");
 
   // remove the previously added key and check the storage is empty
   localStorage.removeItem("key1");
   is(localStorage.length, 0, "The storage is empty [2]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), null, "\'key1\' removed");
 
   is(typeof localStorage.getItem("key1"), "object", "getItem('key1') is object");
   is(typeof localStorage["key1"], "object", "['key1'] is object");
   is(typeof localStorage.key1, "object", "key1 is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
@@ -112,37 +97,37 @@ function startTest()
      (firstKey == 'key2' && secondKey == 'key1'),
      'key() API works.');
 
   // change the second key
   localStorage.setItem("key2", "value2-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1");
   is(localStorage.getItem("key2"), "value2-2");
 
   // change the first key
   localStorage.setItem("key1", "value1-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
   is(localStorage.getItem("key2"), "value2-2");
 
   // remove the second key
   localStorage.removeItem("key2");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
 
   // JS property test
   localStorage.testA = "valueA";
   is(localStorage.testA, "valueA");
   is(localStorage["testA"], "valueA");
   is(localStorage.getItem("testA"), "valueA");
 
@@ -169,19 +154,19 @@ function startTest()
   localStorage.setItem("testC", "valueC2");
   is(localStorage.testC, "valueC2");
   is(localStorage["testC"], "valueC2");
   is(localStorage.getItem("testC"), "valueC2");
 
   // Clear the storage
   localStorage.clear();
   is(localStorage.length, 0, "The storage is empty [3]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(localStorage.getItem("key1"), null, "key1 removed");
   is(localStorage.getItem("key2"), null, "key2 removed");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
   localStorage.removeItem("key1"); // Just check there is no exception
   localStorage.removeItem("key2"); // Just check there is no exception
 
 
--- a/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
+++ b/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
@@ -2,40 +2,25 @@
 <head>
 <title>sessionStorage basic test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-var INDEX_SIZE_ERR = 1;
-
-function checkException(func, exc)
-{
-  var exceptionThrew = false;
-  try {
-    func();
-  }
-  catch (ex) {
-    exceptionThrew = true;
-    is(ex.code, exc, "Expected "+exc+" exception");
-  }
-  ok(exceptionThrew, "Exception "+exc+" threw");
-}
-
 function startTest()
 {
   sessionStorage.clear();
   
   // Initially check the sessionStorage is empty
   is(sessionStorage.length, 0, "The storage is empty [1]");
-  checkException(function() {sessionStorage.key(0);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(sessionStorage["nonexisting"], null, "Nonexisting item is null (array access)");
   is(sessionStorage.nonexisting, null, "Nonexisting item is null (property access)");
   sessionStorage.removeItem("nonexisting"); // Just check there is no exception
 
   is(typeof sessionStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
   is(typeof sessionStorage["nonexisting"], "object", "['nonexisting'] is object");
   is(typeof sessionStorage.nonexisting, "object", "nonexisting is object");
@@ -59,33 +44,33 @@ function startTest()
   is(typeof sessionStorage.getItem("empty"), "object", "getItem('empty') is object");
   is(typeof sessionStorage["empty"], "object", "['empty'] is object");
   is(typeof sessionStorage.empty, "object", "empty is object");
 
   // add one key, check it is there
   sessionStorage.setItem("key1", "value1");
   is(sessionStorage.length, 1, "The storage has one key-value pair");
   is(sessionStorage.key(0), "key1");
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
 
   // check all access method give the correct result
   // and are of the correct type
   is(sessionStorage.getItem("key1"), "value1", "getItem('key1') == value1");
   is(sessionStorage["key1"], "value1", "['key1'] == value1");
   is(sessionStorage.key1, "value1", "key1 == value1");
 
   is(typeof sessionStorage.getItem("key1"), "string", "getItem('key1') is string");
   is(typeof sessionStorage["key1"], "string", "['key1'] is string");
   is(typeof sessionStorage.key1, "string", "key1 is string");
 
   // remove the previously added key and check the storage is empty
   sessionStorage.removeItem("key1");
   is(sessionStorage.length, 0, "The storage is empty [2]");
-  checkException(function() {sessionStorage.key(0);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("key1"), null, "\'key1\' removed");
 
   is(typeof sessionStorage.getItem("key1"), "object", "getItem('key1') is object");
   is(typeof sessionStorage["key1"], "object", "['key1'] is object");
   is(typeof sessionStorage.key1, "object", "key1 is object");
 
   // add one key, check it is there
   sessionStorage.setItem("key1", "value1");
@@ -104,45 +89,45 @@ function startTest()
      (firstKey == 'key2' && secondKey == 'key1'),
      'key() API works.');
 
   // change the second key
   sessionStorage.setItem("key2", "value2-2");
   is(sessionStorage.length, 2, "The storage has two key-value pairs");
   is(sessionStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(sessionStorage.key(1), secondKey);
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(2);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("key1"), "value1");
   is(sessionStorage.getItem("key2"), "value2-2");
 
   // change the first key
   sessionStorage.setItem("key1", "value1-2");
   is(sessionStorage.length, 2, "The storage has two key-value pairs");
   is(sessionStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(sessionStorage.key(1), secondKey);
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(2);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("key1"), "value1-2");
   is(sessionStorage.getItem("key2"), "value2-2");
 
   // remove the second key
   sessionStorage.removeItem("key2");
   is(sessionStorage.length, 1, "The storage has one key-value pair");
   is(sessionStorage.key(0), "key1");
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("key1"), "value1-2");
 
   // Clear the storage
   sessionStorage.clear();
   is(sessionStorage.length, 0, "The storage is empty [3]");
-  checkException(function() {sessionStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(sessionStorage.getItem("key1"), null, "key1 removed");
   is(sessionStorage.getItem("key2"), null, "key2 removed");
   sessionStorage.removeItem("nonexisting"); // Just check there is no exception
   sessionStorage.removeItem("key1"); // Just check there is no exception
   sessionStorage.removeItem("key2"); // Just check there is no exception
 
   SimpleTest.finish();
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/Makefile.in
@@ -0,0 +1,31 @@
+# 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/.
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = dom/tests/mochitest/w3c
+
+DIRS = \
+  $(NULL)
+
+include $(srcdir)/html.mk
+include $(srcdir)/webapps.mk
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_SUPPORT_FILES = \
+  testharness.js \
+  testharnessreport.js \
+  testharness.css \
+  idlharness.js \
+  WebIDLParser.js \
+  $(NULL)
+
+testharnessreport.js: testharnessreport.js.in writeReporter.py 
+	$(PYTHON_PATH) $(srcdir)/writeReporter.py $<
+
+libs:: $(_SUPPORT_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/resources
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/README
@@ -0,0 +1,97 @@
+This directory contains tests imported from W3C test suites. In order to make it
+as easy as possible to update these tests, no changes are made to the imported
+files (names for scripted tests do get a test_ prefix to integrate with the test
+runner, however). The scripts to update tests are provided.
+
+
+=======================
+Files in this directory
+=======================
+
+Source;  Usage and purpose;  License
+
+* testharness.js / testharness.css
+  Directly imported from the W3C repository (<http://dvcs.w3.org/hg/resources>),
+  with the updateTestharness.py script.
+  Provide the test harness.
+  W3C Test Suite License / W3C 3-clause BSD License
+
+* idlharness.js
+  Directly imported from the W3C repository (<http://dvcs.w3.org/hg/resources>),
+  with the updateTestharness.py script.
+  Used to test WebIDL.
+  W3C Test Suite License / W3C 3-clause BSD License
+
+* WebIDLParser.js
+  Directly imported from the W3C repository (<http://dvcs.w3.org/hg/resources>),
+  with the updateTestharness.py script.
+  Used by idlharness.js to parse IDL blocks.
+  MIT License
+
+* updateTestharness.py
+  Used to update the above files.
+  MPL
+
+* parseManifest.py
+  Imported from <https://bitbucket.org/ms2ger/test-runner>. Parses MANIFEST
+  files (provided in the W3C repository) as documented at
+  <https://bitbucket.org/ms2ger/test-runner/raw/tip/manifests.txt>.
+  MIT License
+
+* testharnessreport.js.in
+  Glue between testharness.js and our Mochitest runner.
+  MPL
+
+* importTestsuite.py
+  Imports a test suite from a remote repository. Takes one argument, a file in
+  the format described under webapps.txt.
+  Note: removes both source and destination directory before starting. Do not
+        use with outstanding changes in either directory.
+  MPL
+
+* Makefile.in
+  Integration with our build system. Installs support files into /resources and
+  includes a .mk file for each repository.
+  MPL
+
+* failures.txt
+  List of JSON files with expected failures.
+
+* html.json / webapps.json / ...
+  Expected failures for tests in the webapps repository.
+
+* html.mk / webapps.mk / ...
+  Generated by importTestsuite.py from webapps.txt.
+  Contains a list of the directories with tests. To be included in Makefile.in.
+
+* html.txt / webapps.txt / ...
+  Input to importTestsuite.py.
+  Lists the URL of the repository and the destination directory (separated by a
+  vertical bar), followed by a list of directories within the repository
+  (separated by line feeds).
+
+* html / webapps / ...
+  Actual tests.
+  W3C Test Suite License / W3C 3-clause BSD License
+
+* writeReporter.py
+  Generates testharness.js from testharnessreport.js.in and the JSON files for
+  repositories listed in failures.txt.
+  MPL
+
+
+=====================================================================
+Importing an additional directory from an already-imported repository
+=====================================================================
+
+Add a line to the relevant data file (e.g. webapps.txt), with the path to the
+additional directory relative to the root of the remote repository, and then run
+the importTestsuite.py script, passing the data file as its argument.
+
+
+==========================
+Importing a new test suite
+==========================
+
+Create a data file in the format documented above, and run the
+importTestsuite.py script, passing the data file as its argument.
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/WebIDLParser.js
@@ -0,0 +1,6020 @@
+// From https://github.com/darobin/webidl.js/tree/, under MIT license
+// Forked at https://github.com/ayg/webidl.js
+window.WebIDLParser = (function(){
+  /* Generated by PEG.js 0.6.2 (http://pegjs.majda.cz/). */
+  
+  var result = {
+    /*
+     * Parses the input with a generated parser. If the parsing is successfull,
+     * returns a value explicitly or implicitly specified by the grammar from
+     * which the parser was generated (see |PEG.buildParser|). If the parsing is
+     * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.
+     */
+    parse: function(input, startRule) {
+      var parseFunctions = {
+        "AbsoluteScopedName": parse_AbsoluteScopedName,
+        "Argument": parse_Argument,
+        "Arguments": parse_Arguments,
+        "ArgumentsRest": parse_ArgumentsRest,
+        "ArrayType": parse_ArrayType,
+        "Attribute": parse_Attribute,
+        "BooleanLiteral": parse_BooleanLiteral,
+        "ExtAttr": parse_ExtAttr,
+        "ExtAttrArgList": parse_ExtAttrArgList,
+        "ExtAttrNameValue": parse_ExtAttrNameValue,
+        "ExtAttrNamedArgList": parse_ExtAttrNamedArgList,
+        "ExtAttrNoArg": parse_ExtAttrNoArg,
+        "ExtAttrs": parse_ExtAttrs,
+        "ExtAttrsRest": parse_ExtAttrsRest,
+        "GetRaises": parse_GetRaises,
+        "Nullable": parse_Nullable,
+        "Operation": parse_Operation,
+        "OperationRest": parse_OperationRest,
+        "PrimitiveType": parse_PrimitiveType,
+        "Qualifiers": parse_Qualifiers,
+        "Raises": parse_Raises,
+        "RelativeScopedName": parse_RelativeScopedName,
+        "ReturnType": parse_ReturnType,
+        "ScopedName": parse_ScopedName,
+        "ScopedNameList": parse_ScopedNameList,
+        "ScopedNameListRest": parse_ScopedNameListRest,
+        "ScopedNameRest": parse_ScopedNameRest,
+        "Sequence": parse_Sequence,
+        "SetRaises": parse_SetRaises,
+        "SimpleType": parse_SimpleType,
+        "Special": parse_Special,
+        "Stringifier": parse_Stringifier,
+        "TypeDesc": parse_TypeDesc,
+        "UnsignedIntegerType": parse_UnsignedIntegerType,
+        "attrOrOp": parse_attrOrOp,
+        "const": parse_const,
+        "constExpr": parse_constExpr,
+        "decimal": parse_decimal,
+        "defaultValue": parse_defaultValue,
+        "definition": parse_definition,
+        "definitions": parse_definitions,
+        "dictionary": parse_dictionary,
+        "dictionaryMember": parse_dictionaryMember,
+        "dotFloat": parse_dotFloat,
+        "exMember": parse_exMember,
+        "exception": parse_exception,
+        "expFloat": parse_expFloat,
+        "extendedAttributeList": parse_extendedAttributeList,
+        "field": parse_field,
+        "float": parse_float,
+        "floatEe": parse_floatEe,
+        "hex": parse_hex,
+        "identifier": parse_identifier,
+        "ifInheritance": parse_ifInheritance,
+        "ifMember": parse_ifMember,
+        "implements": parse_implements,
+        "integer": parse_integer,
+        "interface": parse_interface,
+        "leadFloat": parse_leadFloat,
+        "module": parse_module,
+        "octal": parse_octal,
+        "other": parse_other,
+        "partialinterface": parse_partialinterface,
+        "s": parse_s,
+        "space": parse_space,
+        "string": parse_string,
+        "type": parse_type,
+        "typedef": parse_typedef,
+        "w": parse_w
+      };
+      
+      if (startRule !== undefined) {
+        if (parseFunctions[startRule] === undefined) {
+          throw new Error("Invalid rule name: " + quote(startRule) + ".");
+        }
+      } else {
+        startRule = "definitions";
+      }
+      
+      var pos = 0;
+      var reportMatchFailures = true;
+      var rightmostMatchFailuresPos = 0;
+      var rightmostMatchFailuresExpected = [];
+      var cache = {};
+      
+      function padLeft(input, padding, length) {
+        var result = input;
+        
+        var padLength = length - input.length;
+        for (var i = 0; i < padLength; i++) {
+          result = padding + result;
+        }
+        
+        return result;
+      }
+      
+      function escape(ch) {
+        var charCode = ch.charCodeAt(0);
+        
+        if (charCode <= 0xFF) {
+          var escapeChar = 'x';
+          var length = 2;
+        } else {
+          var escapeChar = 'u';
+          var length = 4;
+        }
+        
+        return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
+      }
+      
+      function quote(s) {
+        /*
+         * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a
+         * string literal except for the closing quote character, backslash,
+         * carriage return, line separator, paragraph separator, and line feed.
+         * Any character may appear in the form of an escape sequence.
+         */
+        return '"' + s
+          .replace(/\\/g, '\\\\')            // backslash
+          .replace(/"/g, '\\"')              // closing quote character
+          .replace(/\r/g, '\\r')             // carriage return
+          .replace(/\n/g, '\\n')             // line feed
+          .replace(/[\x80-\uFFFF]/g, escape) // non-ASCII characters
+          + '"';
+      }
+      
+      function matchFailed(failure) {
+        if (pos < rightmostMatchFailuresPos) {
+          return;
+        }
+        
+        if (pos > rightmostMatchFailuresPos) {
+          rightmostMatchFailuresPos = pos;
+          rightmostMatchFailuresExpected = [];
+        }
+        
+        rightmostMatchFailuresExpected.push(failure);
+      }
+      
+      function parse_space() {
+        var cacheKey = 'space@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        if (input.substr(pos, 1) === " ") {
+          var result20 = " ";
+          pos += 1;
+        } else {
+          var result20 = null;
+          if (reportMatchFailures) {
+            matchFailed("\" \"");
+          }
+        }
+        if (result20 !== null) {
+          var result0 = result20;
+        } else {
+          if (input.substr(pos, 1) === "	") {
+            var result19 = "	";
+            pos += 1;
+          } else {
+            var result19 = null;
+            if (reportMatchFailures) {
+              matchFailed("\"	\"");
+            }
+          }
+          if (result19 !== null) {
+            var result0 = result19;
+          } else {
+            if (input.substr(pos, 1) === "\r") {
+              var result18 = "\r";
+              pos += 1;
+            } else {
+              var result18 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"\\r\"");
+              }
+            }
+            if (result18 !== null) {
+              var result0 = result18;
+            } else {
+              if (input.substr(pos, 1) === "\n") {
+                var result17 = "\n";
+                pos += 1;
+              } else {
+                var result17 = null;
+                if (reportMatchFailures) {
+                  matchFailed("\"\\n\"");
+                }
+              }
+              if (result17 !== null) {
+                var result0 = result17;
+              } else {
+                if (input.substr(pos, 1) === "") {
+                  var result16 = "";
+                  pos += 1;
+                } else {
+                  var result16 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\"\"");
+                  }
+                }
+                if (result16 !== null) {
+                  var result0 = result16;
+                } else {
+                  var savedPos3 = pos;
+                  if (input.substr(pos, 2) === "//") {
+                    var result12 = "//";
+                    pos += 2;
+                  } else {
+                    var result12 = null;
+                    if (reportMatchFailures) {
+                      matchFailed("\"//\"");
+                    }
+                  }
+                  if (result12 !== null) {
+                    var result13 = [];
+                    if (input.substr(pos).match(/^[^\n]/) !== null) {
+                      var result15 = input.charAt(pos);
+                      pos++;
+                    } else {
+                      var result15 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("[^\\n]");
+                      }
+                    }
+                    while (result15 !== null) {
+                      result13.push(result15);
+                      if (input.substr(pos).match(/^[^\n]/) !== null) {
+                        var result15 = input.charAt(pos);
+                        pos++;
+                      } else {
+                        var result15 = null;
+                        if (reportMatchFailures) {
+                          matchFailed("[^\\n]");
+                        }
+                      }
+                    }
+                    if (result13 !== null) {
+                      if (input.substr(pos, 1) === "\n") {
+                        var result14 = "\n";
+                        pos += 1;
+                      } else {
+                        var result14 = null;
+                        if (reportMatchFailures) {
+                          matchFailed("\"\\n\"");
+                        }
+                      }
+                      if (result14 !== null) {
+                        var result11 = [result12, result13, result14];
+                      } else {
+                        var result11 = null;
+                        pos = savedPos3;
+                      }
+                    } else {
+                      var result11 = null;
+                      pos = savedPos3;
+                    }
+                  } else {
+                    var result11 = null;
+                    pos = savedPos3;
+                  }
+                  if (result11 !== null) {
+                    var result0 = result11;
+                  } else {
+                    var savedPos0 = pos;
+                    if (input.substr(pos, 2) === "/*") {
+                      var result2 = "/*";
+                      pos += 2;
+                    } else {
+                      var result2 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("\"/*\"");
+                      }
+                    }
+                    if (result2 !== null) {
+                      var result3 = [];
+                      if (input.substr(pos).match(/^[^*]/) !== null) {
+                        var result10 = input.charAt(pos);
+                        pos++;
+                      } else {
+                        var result10 = null;
+                        if (reportMatchFailures) {
+                          matchFailed("[^*]");
+                        }
+                      }
+                      if (result10 !== null) {
+                        var result5 = result10;
+                      } else {
+                        var savedPos1 = pos;
+                        if (input.substr(pos, 1) === "*") {
+                          var result7 = "*";
+                          pos += 1;
+                        } else {
+                          var result7 = null;
+                          if (reportMatchFailures) {
+                            matchFailed("\"*\"");
+                          }
+                        }
+                        if (result7 !== null) {
+                          var savedPos2 = pos;
+                          var savedReportMatchFailuresVar0 = reportMatchFailures;
+                          reportMatchFailures = false;
+                          if (input.substr(pos, 1) === "/") {
+                            var result9 = "/";
+                            pos += 1;
+                          } else {
+                            var result9 = null;
+                            if (reportMatchFailures) {
+                              matchFailed("\"/\"");
+                            }
+                          }
+                          reportMatchFailures = savedReportMatchFailuresVar0;
+                          if (result9 === null) {
+                            var result8 = '';
+                          } else {
+                            var result8 = null;
+                            pos = savedPos2;
+                          }
+                          if (result8 !== null) {
+                            var result6 = [result7, result8];
+                          } else {
+                            var result6 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result6 = null;
+                          pos = savedPos1;
+                        }
+                        if (result6 !== null) {
+                          var result5 = result6;
+                        } else {
+                          var result5 = null;;
+                        };
+                      }
+                      while (result5 !== null) {
+                        result3.push(result5);
+                        if (input.substr(pos).match(/^[^*]/) !== null) {
+                          var result10 = input.charAt(pos);
+                          pos++;
+                        } else {
+                          var result10 = null;
+                          if (reportMatchFailures) {
+                            matchFailed("[^*]");
+                          }
+                        }
+                        if (result10 !== null) {
+                          var result5 = result10;
+                        } else {
+                          var savedPos1 = pos;
+                          if (input.substr(pos, 1) === "*") {
+                            var result7 = "*";
+                            pos += 1;
+                          } else {
+                            var result7 = null;
+                            if (reportMatchFailures) {
+                              matchFailed("\"*\"");
+                            }
+                          }
+                          if (result7 !== null) {
+                            var savedPos2 = pos;
+                            var savedReportMatchFailuresVar0 = reportMatchFailures;
+                            reportMatchFailures = false;
+                            if (input.substr(pos, 1) === "/") {
+                              var result9 = "/";
+                              pos += 1;
+                            } else {
+                              var result9 = null;
+                              if (reportMatchFailures) {
+                                matchFailed("\"/\"");
+                              }
+                            }
+                            reportMatchFailures = savedReportMatchFailuresVar0;
+                            if (result9 === null) {
+                              var result8 = '';
+                            } else {
+                              var result8 = null;
+                              pos = savedPos2;
+                            }
+                            if (result8 !== null) {
+                              var result6 = [result7, result8];
+                            } else {
+                              var result6 = null;
+                              pos = savedPos1;
+                            }
+                          } else {
+                            var result6 = null;
+                            pos = savedPos1;
+                          }
+                          if (result6 !== null) {
+                            var result5 = result6;
+                          } else {
+                            var result5 = null;;
+                          };
+                        }
+                      }
+                      if (result3 !== null) {
+                        if (input.substr(pos, 2) === "*/") {
+                          var result4 = "*/";
+                          pos += 2;
+                        } else {
+                          var result4 = null;
+                          if (reportMatchFailures) {
+                            matchFailed("\"*/\"");
+                          }
+                        }
+                        if (result4 !== null) {
+                          var result1 = [result2, result3, result4];
+                        } else {
+                          var result1 = null;
+                          pos = savedPos0;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos0;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos0;
+                    }
+                    if (result1 !== null) {
+                      var result0 = result1;
+                    } else {
+                      var result0 = null;;
+                    };
+                  };
+                };
+              };
+            };
+          };
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_s() {
+        var cacheKey = 's@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var result1 = parse_space();
+        if (result1 !== null) {
+          var result0 = [];
+          while (result1 !== null) {
+            result0.push(result1);
+            var result1 = parse_space();
+          }
+        } else {
+          var result0 = null;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_w() {
+        var cacheKey = 'w@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var result1 = parse_s();
+        var result0 = result1 !== null ? result1 : '';
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_identifier() {
+        var cacheKey = 'identifier@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos).match(/^[A-Z_a-z]/) !== null) {
+          var result3 = input.charAt(pos);
+          pos++;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("[A-Z_a-z]");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = [];
+          if (input.substr(pos).match(/^[0-9A-Z_a-z]/) !== null) {
+            var result5 = input.charAt(pos);
+            pos++;
+          } else {
+            var result5 = null;
+            if (reportMatchFailures) {
+              matchFailed("[0-9A-Z_a-z]");
+            }
+          }
+          while (result5 !== null) {
+            result4.push(result5);
+            if (input.substr(pos).match(/^[0-9A-Z_a-z]/) !== null) {
+              var result5 = input.charAt(pos);
+              pos++;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("[0-9A-Z_a-z]");
+              }
+            }
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(nmstart, nmchars) { return nmstart + nmchars.join(""); })(result1[0], result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_octal() {
+        var cacheKey = 'octal@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 1) === "0") {
+          var result3 = "0";
+          pos += 1;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"0\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = [];
+          if (input.substr(pos).match(/^[0-7]/) !== null) {
+            var result5 = input.charAt(pos);
+            pos++;
+          } else {
+            var result5 = null;
+            if (reportMatchFailures) {
+              matchFailed("[0-7]");
+            }
+          }
+          while (result5 !== null) {
+            result4.push(result5);
+            if (input.substr(pos).match(/^[0-7]/) !== null) {
+              var result5 = input.charAt(pos);
+              pos++;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("[0-7]");
+              }
+            }
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(value) { return "0" + value.join(""); })(result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_hex() {
+        var cacheKey = 'hex@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 1) === "0") {
+          var result3 = "0";
+          pos += 1;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"0\"");
+          }
+        }
+        if (result3 !== null) {
+          if (input.substr(pos).match(/^[Xx]/) !== null) {
+            var result4 = input.charAt(pos);
+            pos++;
+          } else {
+            var result4 = null;
+            if (reportMatchFailures) {
+              matchFailed("[Xx]");
+            }
+          }
+          if (result4 !== null) {
+            if (input.substr(pos).match(/^[0-9A-Fa-f]/) !== null) {
+              var result6 = input.charAt(pos);
+              pos++;
+            } else {
+              var result6 = null;
+              if (reportMatchFailures) {
+                matchFailed("[0-9A-Fa-f]");
+              }
+            }
+            if (result6 !== null) {
+              var result5 = [];
+              while (result6 !== null) {
+                result5.push(result6);
+                if (input.substr(pos).match(/^[0-9A-Fa-f]/) !== null) {
+                  var result6 = input.charAt(pos);
+                  pos++;
+                } else {
+                  var result6 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("[0-9A-Fa-f]");
+                  }
+                }
+              }
+            } else {
+              var result5 = null;
+            }
+            if (result5 !== null) {
+              var result1 = [result3, result4, result5];
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(x, value) { return "0" + x + value.join(""); })(result1[1], result1[2])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_decimal() {
+        var cacheKey = 'decimal@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos).match(/^[0-9]/) !== null) {
+          var result3 = input.charAt(pos);
+          pos++;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("[0-9]");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = [];
+          if (input.substr(pos).match(/^[0-9]/) !== null) {
+            var result5 = input.charAt(pos);
+            pos++;
+          } else {
+            var result5 = null;
+            if (reportMatchFailures) {
+              matchFailed("[0-9]");
+            }
+          }
+          while (result5 !== null) {
+            result4.push(result5);
+            if (input.substr(pos).match(/^[0-9]/) !== null) {
+              var result5 = input.charAt(pos);
+              pos++;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("[0-9]");
+              }
+            }
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(numStart, numRest) { return numStart + numRest.join(""); })(result1[0], result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_integer() {
+        var cacheKey = 'integer@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 1) === "-") {
+          var result8 = "-";
+          pos += 1;
+        } else {
+          var result8 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"-\"");
+          }
+        }
+        var result3 = result8 !== null ? result8 : '';
+        if (result3 !== null) {
+          var result7 = parse_hex();
+          if (result7 !== null) {
+            var result4 = result7;
+          } else {
+            var result6 = parse_octal();
+            if (result6 !== null) {
+              var result4 = result6;
+            } else {
+              var result5 = parse_decimal();
+              if (result5 !== null) {
+                var result4 = result5;
+              } else {
+                var result4 = null;;
+              };
+            };
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(neg, num) { return neg + num; })(result1[0], result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_floatEe() {
+        var cacheKey = 'floatEe@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos).match(/^[Ee]/) !== null) {
+          var result3 = input.charAt(pos);
+          pos++;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("[Ee]");
+          }
+        }
+        if (result3 !== null) {
+          if (input.substr(pos).match(/^[+\-]/) !== null) {
+            var result7 = input.charAt(pos);
+            pos++;
+          } else {
+            var result7 = null;
+            if (reportMatchFailures) {
+              matchFailed("[+\\-]");
+            }
+          }
+          var result4 = result7 !== null ? result7 : '';
+          if (result4 !== null) {
+            if (input.substr(pos).match(/^[0-9]/) !== null) {
+              var result6 = input.charAt(pos);
+              pos++;
+            } else {
+              var result6 = null;
+              if (reportMatchFailures) {
+                matchFailed("[0-9]");
+              }
+            }
+            if (result6 !== null) {
+              var result5 = [];
+              while (result6 !== null) {
+                result5.push(result6);
+                if (input.substr(pos).match(/^[0-9]/) !== null) {
+                  var result6 = input.charAt(pos);
+                  pos++;
+                } else {
+                  var result6 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("[0-9]");
+                  }
+                }
+              }
+            } else {
+              var result5 = null;
+            }
+            if (result5 !== null) {
+              var result1 = [result3, result4, result5];
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(e, sign, exp) { return e + sign + exp.join(""); })(result1[0], result1[1], result1[2])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_expFloat() {
+        var cacheKey = 'expFloat@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos).match(/^[0-9]/) !== null) {
+          var result5 = input.charAt(pos);
+          pos++;
+        } else {
+          var result5 = null;
+          if (reportMatchFailures) {
+            matchFailed("[0-9]");
+          }
+        }
+        if (result5 !== null) {
+          var result3 = [];
+          while (result5 !== null) {
+            result3.push(result5);
+            if (input.substr(pos).match(/^[0-9]/) !== null) {
+              var result5 = input.charAt(pos);
+              pos++;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("[0-9]");
+              }
+            }
+          }
+        } else {
+          var result3 = null;
+        }
+        if (result3 !== null) {
+          var result4 = parse_floatEe();
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(num, fee) { return num.join("") + fee; })(result1[0], result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_leadFloat() {
+        var cacheKey = 'leadFloat@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos).match(/^[0-9]/) !== null) {
+          var result9 = input.charAt(pos);
+          pos++;
+        } else {
+          var result9 = null;
+          if (reportMatchFailures) {
+            matchFailed("[0-9]");
+          }
+        }
+        if (result9 !== null) {
+          var result3 = [];
+          while (result9 !== null) {
+            result3.push(result9);
+            if (input.substr(pos).match(/^[0-9]/) !== null) {
+              var result9 = input.charAt(pos);
+              pos++;
+            } else {
+              var result9 = null;
+              if (reportMatchFailures) {
+                matchFailed("[0-9]");
+              }
+            }
+          }
+        } else {
+          var result3 = null;
+        }
+        if (result3 !== null) {
+          if (input.substr(pos, 1) === ".") {
+            var result4 = ".";
+            pos += 1;
+          } else {
+            var result4 = null;
+            if (reportMatchFailures) {
+              matchFailed("\".\"");
+            }
+          }
+          if (result4 !== null) {
+            var result5 = [];
+            if (input.substr(pos).match(/^[0-9]/) !== null) {
+              var result8 = input.charAt(pos);
+              pos++;
+            } else {
+              var result8 = null;
+              if (reportMatchFailures) {
+                matchFailed("[0-9]");
+              }
+            }
+            while (result8 !== null) {
+              result5.push(result8);
+              if (input.substr(pos).match(/^[0-9]/) !== null) {
+                var result8 = input.charAt(pos);
+                pos++;
+              } else {
+                var result8 = null;
+                if (reportMatchFailures) {
+                  matchFailed("[0-9]");
+                }
+              }
+            }
+            if (result5 !== null) {
+              var result7 = parse_floatEe();
+              var result6 = result7 !== null ? result7 : '';
+              if (result6 !== null) {
+                var result1 = [result3, result4, result5, result6];
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(num, dec, fee) { return num.join("") + "." + dec.join("") + fee; })(result1[0], result1[2], result1[3])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_dotFloat() {
+        var cacheKey = 'dotFloat@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = [];
+        if (input.substr(pos).match(/^[0-9]/) !== null) {
+          var result9 = input.charAt(pos);
+          pos++;
+        } else {
+          var result9 = null;
+          if (reportMatchFailures) {
+            matchFailed("[0-9]");
+          }
+        }
+        while (result9 !== null) {
+          result3.push(result9);
+          if (input.substr(pos).match(/^[0-9]/) !== null) {
+            var result9 = input.charAt(pos);
+            pos++;
+          } else {
+            var result9 = null;
+            if (reportMatchFailures) {
+              matchFailed("[0-9]");
+            }
+          }
+        }
+        if (result3 !== null) {
+          if (input.substr(pos, 1) === ".") {
+            var result4 = ".";
+            pos += 1;
+          } else {
+            var result4 = null;
+            if (reportMatchFailures) {
+              matchFailed("\".\"");
+            }
+          }
+          if (result4 !== null) {
+            if (input.substr(pos).match(/^[0-9]/) !== null) {
+              var result8 = input.charAt(pos);
+              pos++;
+            } else {
+              var result8 = null;
+              if (reportMatchFailures) {
+                matchFailed("[0-9]");
+              }
+            }
+            if (result8 !== null) {
+              var result5 = [];
+              while (result8 !== null) {
+                result5.push(result8);
+                if (input.substr(pos).match(/^[0-9]/) !== null) {
+                  var result8 = input.charAt(pos);
+                  pos++;
+                } else {
+                  var result8 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("[0-9]");
+                  }
+                }
+              }
+            } else {
+              var result5 = null;
+            }
+            if (result5 !== null) {
+              var result7 = parse_floatEe();
+              var result6 = result7 !== null ? result7 : '';
+              if (result6 !== null) {
+                var result1 = [result3, result4, result5, result6];
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(num, dec, fee) { return num.join("") + "." + dec.join("") + fee; })(result1[0], result1[2], result1[3])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_float() {
+        var cacheKey = 'float@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 1) === "-") {
+          var result8 = "-";
+          pos += 1;
+        } else {
+          var result8 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"-\"");
+          }
+        }
+        var result3 = result8 !== null ? result8 : '';
+        if (result3 !== null) {
+          var result7 = parse_leadFloat();
+          if (result7 !== null) {
+            var result4 = result7;
+          } else {
+            var result6 = parse_dotFloat();
+            if (result6 !== null) {
+              var result4 = result6;
+            } else {
+              var result5 = parse_expFloat();
+              if (result5 !== null) {
+                var result4 = result5;
+              } else {
+                var result4 = null;;
+              };
+            };
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(neg, num) { return neg + num; })(result1[0], result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_string() {
+        var cacheKey = 'string@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 1) === "\"") {
+          var result3 = "\"";
+          pos += 1;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"\\\"\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = [];
+          if (input.substr(pos).match(/^[^""]/) !== null) {
+            var result6 = input.charAt(pos);
+            pos++;
+          } else {
+            var result6 = null;
+            if (reportMatchFailures) {
+              matchFailed("[^\"\"]");
+            }
+          }
+          while (result6 !== null) {
+            result4.push(result6);
+            if (input.substr(pos).match(/^[^""]/) !== null) {
+              var result6 = input.charAt(pos);
+              pos++;
+            } else {
+              var result6 = null;
+              if (reportMatchFailures) {
+                matchFailed("[^\"\"]");
+              }
+            }
+          }
+          if (result4 !== null) {
+            if (input.substr(pos, 1) === "\"") {
+              var result5 = "\"";
+              pos += 1;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"\\\"\"");
+              }
+            }
+            if (result5 !== null) {
+              var result1 = [result3, result4, result5];
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(str) { return str.join(""); })(result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_other() {
+        var cacheKey = 'other@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        if (input.substr(pos).match(/^[^	\n\r 0-9A-Z_a-z]/) !== null) {
+          var result3 = input.charAt(pos);
+          pos++;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("[^	\\n\\r 0-9A-Z_a-z]");
+          }
+        }
+        if (result3 !== null) {
+          var result1 = [];
+          while (result3 !== null) {
+            result1.push(result3);
+            if (input.substr(pos).match(/^[^	\n\r 0-9A-Z_a-z]/) !== null) {
+              var result3 = input.charAt(pos);
+              pos++;
+            } else {
+              var result3 = null;
+              if (reportMatchFailures) {
+                matchFailed("[^	\\n\\r 0-9A-Z_a-z]");
+              }
+            }
+          }
+        } else {
+          var result1 = null;
+        }
+        var result2 = result1 !== null
+          ? (function(other) { return other.join(""); })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_type() {
+        var cacheKey = 'type@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_TypeDesc();
+        if (result3 !== null) {
+          var result4 = parse_Nullable();
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(type, nullable) {
+                      if (!type.sequence) type.sequence = false;
+                      type.nullable = nullable;
+                      return type; })(result1[0], result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_TypeDesc() {
+        var cacheKey = 'TypeDesc@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var result5 = parse_Sequence();
+        if (result5 !== null) {
+          var result1 = result5;
+        } else {
+          var result4 = parse_ArrayType();
+          if (result4 !== null) {
+            var result1 = result4;
+          } else {
+            var result3 = parse_SimpleType();
+            if (result3 !== null) {
+              var result1 = result3;
+            } else {
+              var result1 = null;;
+            };
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(type) { return type; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_Sequence() {
+        var cacheKey = 'Sequence@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 9) === "sequence<") {
+          var result3 = "sequence<";
+          pos += 9;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"sequence<\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_type();
+          if (result4 !== null) {
+            if (input.substr(pos, 1) === ">") {
+              var result5 = ">";
+              pos += 1;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\">\"");
+              }
+            }
+            if (result5 !== null) {
+              var result1 = [result3, result4, result5];
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(type) { return { sequence: true, array: false, idlType: type }; })(result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ArrayType() {
+        var cacheKey = 'ArrayType@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_SimpleType();
+        if (result3 !== null) {
+          if (input.substr(pos, 2) === "[]") {
+            var result4 = "[]";
+            pos += 2;
+          } else {
+            var result4 = null;
+            if (reportMatchFailures) {
+              matchFailed("\"[]\"");
+            }
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(type) {
+                      type.array = true;
+                      return type;
+                  })(result1[0])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_SimpleType() {
+        var cacheKey = 'SimpleType@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var result5 = parse_PrimitiveType();
+        if (result5 !== null) {
+          var result1 = result5;
+        } else {
+          var result4 = parse_UnsignedIntegerType();
+          if (result4 !== null) {
+            var result1 = result4;
+          } else {
+            var result3 = parse_ScopedName();
+            if (result3 !== null) {
+              var result1 = result3;
+            } else {
+              var result1 = null;;
+            };
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(type) { return { sequence: false, array: false, idlType: type }; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_PrimitiveType() {
+        var cacheKey = 'PrimitiveType@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 3) === "any") {
+          var result12 = "any";
+          pos += 3;
+        } else {
+          var result12 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"any\"");
+          }
+        }
+        if (result12 !== null) {
+          var result3 = result12;
+        } else {
+          if (input.substr(pos, 6) === "object") {
+            var result11 = "object";
+            pos += 6;
+          } else {
+            var result11 = null;
+            if (reportMatchFailures) {
+              matchFailed("\"object\"");
+            }
+          }
+          if (result11 !== null) {
+            var result3 = result11;
+          } else {
+            if (input.substr(pos, 7) === "boolean") {
+              var result10 = "boolean";
+              pos += 7;
+            } else {
+              var result10 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"boolean\"");
+              }
+            }
+            if (result10 !== null) {
+              var result3 = result10;
+            } else {
+              if (input.substr(pos, 5) === "octet") {
+                var result9 = "octet";
+                pos += 5;
+              } else {
+                var result9 = null;
+                if (reportMatchFailures) {
+                  matchFailed("\"octet\"");
+                }
+              }
+              if (result9 !== null) {
+                var result3 = result9;
+              } else {
+                if (input.substr(pos, 5) === "float") {
+                  var result8 = "float";
+                  pos += 5;
+                } else {
+                  var result8 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\"float\"");
+                  }
+                }
+                if (result8 !== null) {
+                  var result3 = result8;
+                } else {
+                  if (input.substr(pos, 6) === "double") {
+                    var result7 = "double";
+                    pos += 6;
+                  } else {
+                    var result7 = null;
+                    if (reportMatchFailures) {
+                      matchFailed("\"double\"");
+                    }
+                  }
+                  if (result7 !== null) {
+                    var result3 = result7;
+                  } else {
+                    if (input.substr(pos, 9) === "DOMString") {
+                      var result6 = "DOMString";
+                      pos += 9;
+                    } else {
+                      var result6 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("\"DOMString\"");
+                      }
+                    }
+                    if (result6 !== null) {
+                      var result3 = result6;
+                    } else {
+                      var result3 = null;;
+                    };
+                  };
+                };
+              };
+            };
+          };
+        }
+        if (result3 !== null) {
+          var savedPos2 = pos;
+          var savedReportMatchFailuresVar0 = reportMatchFailures;
+          reportMatchFailures = false;
+          if (input.substr(pos).match(/^[A-Za-z0-9]/) !== null) {
+            var result5 = input.charAt(pos);
+            pos++;
+          } else {
+            var result5 = null;
+            if (reportMatchFailures) {
+              matchFailed("[A-Za-z0-9]");
+            }
+          }
+          reportMatchFailures = savedReportMatchFailuresVar0;
+          if (result5 === null) {
+            var result4 = '';
+          } else {
+            var result4 = null;
+            pos = savedPos2;
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(type) { return type; })(result1[0])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_UnsignedIntegerType() {
+        var cacheKey = 'UnsignedIntegerType@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 8) === "unsigned") {
+          var result13 = "unsigned";
+          pos += 8;
+        } else {
+          var result13 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"unsigned\"");
+          }
+        }
+        var result3 = result13 !== null ? result13 : '';
+        if (result3 !== null) {
+          var result4 = parse_s();
+          if (result4 !== null) {
+            var savedPos2 = pos;
+            if (input.substr(pos, 4) === "long") {
+              var result10 = "long";
+              pos += 4;
+            } else {
+              var result10 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"long\"");
+              }
+            }
+            if (result10 !== null) {
+              var result11 = parse_s();
+              if (result11 !== null) {
+                if (input.substr(pos, 4) === "long") {
+                  var result12 = "long";
+                  pos += 4;
+                } else {
+                  var result12 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\"long\"");
+                  }
+                }
+                if (result12 !== null) {
+                  var result9 = [result10, result11, result12];
+                } else {
+                  var result9 = null;
+                  pos = savedPos2;
+                }
+              } else {
+                var result9 = null;
+                pos = savedPos2;
+              }
+            } else {
+              var result9 = null;
+              pos = savedPos2;
+            }
+            if (result9 !== null) {
+              var result5 = result9;
+            } else {
+              if (input.substr(pos, 4) === "long") {
+                var result8 = "long";
+                pos += 4;
+              } else {
+                var result8 = null;
+                if (reportMatchFailures) {
+                  matchFailed("\"long\"");
+                }
+              }
+              if (result8 !== null) {
+                var result5 = result8;
+              } else {
+                if (input.substr(pos, 5) === "short") {
+                  var result7 = "short";
+                  pos += 5;
+                } else {
+                  var result7 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\"short\"");
+                  }
+                }
+                if (result7 !== null) {
+                  var result5 = result7;
+                } else {
+                  if (input.substr(pos, 4) === "byte") {
+                    var result6 = "byte";
+                    pos += 4;
+                  } else {
+                    var result6 = null;
+                    if (reportMatchFailures) {
+                      matchFailed("\"byte\"");
+                    }
+                  }
+                  if (result6 !== null) {
+                    var result5 = result6;
+                  } else {
+                    var result5 = null;;
+                  };
+                };
+              };
+            }
+            if (result5 !== null) {
+              var result1 = [result3, result4, result5];
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(uns, kind) { return (uns ? "unsigned " : "") + (kind.join ? kind.join("") : kind); })(result1[0], result1[2])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ScopedNameList() {
+        var cacheKey = 'ScopedNameList@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_ScopedName();
+        if (result3 !== null) {
+          var result4 = [];
+          var result5 = parse_ScopedNameListRest();
+          while (result5 !== null) {
+            result4.push(result5);
+            var result5 = parse_ScopedNameListRest();
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(first, others) {   var ret = [first];
+                      for (var i = 0, n = others.length; i < n; i++) { ret.push(others[i]); }
+                      return ret; })(result1[0], result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ScopedNameListRest() {
+        var cacheKey = 'ScopedNameListRest@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_w();
+        if (result3 !== null) {
+          if (input.substr(pos, 1) === ",") {
+            var result4 = ",";
+            pos += 1;
+          } else {
+            var result4 = null;
+            if (reportMatchFailures) {
+              matchFailed("\",\"");
+            }
+          }
+          if (result4 !== null) {
+            var result5 = parse_w();
+            if (result5 !== null) {
+              var result6 = parse_ScopedName();
+              if (result6 !== null) {
+                var result1 = [result3, result4, result5, result6];
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(rest) { return rest; })(result1[3])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ScopedName() {
+        var cacheKey = 'ScopedName@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var result4 = parse_AbsoluteScopedName();
+        if (result4 !== null) {
+          var result1 = result4;
+        } else {
+          var result3 = parse_RelativeScopedName();
+          if (result3 !== null) {
+            var result1 = result3;
+          } else {
+            var result1 = null;;
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(name) { return name; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_AbsoluteScopedName() {
+        var cacheKey = 'AbsoluteScopedName@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 2) === "::") {
+          var result3 = "::";
+          pos += 2;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"::\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_RelativeScopedName();
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(rel) { return "::" + rel; })(result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_RelativeScopedName() {
+        var cacheKey = 'RelativeScopedName@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_identifier();
+        if (result3 !== null) {
+          var result4 = [];
+          var result5 = parse_ScopedNameRest();
+          while (result5 !== null) {
+            result4.push(result5);
+            var result5 = parse_ScopedNameRest();
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(name, rest) { return name + rest.join(""); })(result1[0], result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ScopedNameRest() {
+        var cacheKey = 'ScopedNameRest@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 2) === "::") {
+          var result3 = "::";
+          pos += 2;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"::\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_identifier();
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(name) { return name.join(""); })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_BooleanLiteral() {
+        var cacheKey = 'BooleanLiteral@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        if (input.substr(pos, 4) === "true") {
+          var result4 = "true";
+          pos += 4;
+        } else {
+          var result4 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"true\"");
+          }
+        }
+        if (result4 !== null) {
+          var result1 = result4;
+        } else {
+          if (input.substr(pos, 5) === "false") {
+            var result3 = "false";
+            pos += 5;
+          } else {
+            var result3 = null;
+            if (reportMatchFailures) {
+              matchFailed("\"false\"");
+            }
+          }
+          if (result3 !== null) {
+            var result1 = result3;
+          } else {
+            var result1 = null;;
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(value) { return value; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_Nullable() {
+        var cacheKey = 'Nullable@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        if (input.substr(pos, 1) === "?") {
+          var result3 = "?";
+          pos += 1;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"?\"");
+          }
+        }
+        var result1 = result3 !== null ? result3 : '';
+        var result2 = result1 !== null
+          ? (function(nullable) { return nullable ? true : false; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ReturnType() {
+        var cacheKey = 'ReturnType@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        if (input.substr(pos, 4) === "void") {
+          var result4 = "void";
+          pos += 4;
+        } else {
+          var result4 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"void\"");
+          }
+        }
+        if (result4 !== null) {
+          var result1 = result4;
+        } else {
+          var result3 = parse_type();
+          if (result3 !== null) {
+            var result1 = result3;
+          } else {
+            var result1 = null;;
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(ret) { return ret; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_definitions() {
+        var cacheKey = 'definitions@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_w();
+        if (result3 !== null) {
+          var result4 = [];
+          var result5 = parse_definition();
+          while (result5 !== null) {
+            result4.push(result5);
+            var result5 = parse_definition();
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(defs) { return defs; })(result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_definition() {
+        var cacheKey = 'definition@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var result9 = parse_partialinterface();
+        if (result9 !== null) {
+          var result1 = result9;
+        } else {
+          var result8 = parse_module();
+          if (result8 !== null) {
+            var result1 = result8;
+          } else {
+            var result7 = parse_interface();
+            if (result7 !== null) {
+              var result1 = result7;
+            } else {
+              var result6 = parse_dictionary();
+              if (result6 !== null) {
+                var result1 = result6;
+              } else {
+                var result5 = parse_typedef();
+                if (result5 !== null) {
+                  var result1 = result5;
+                } else {
+                  var result4 = parse_exception();
+                  if (result4 !== null) {
+                    var result1 = result4;
+                  } else {
+                    var result3 = parse_implements();
+                    if (result3 !== null) {
+                      var result1 = result3;
+                    } else {
+                      var result1 = null;;
+                    };
+                  };
+                };
+              };
+            };
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(def) { return def; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_partialinterface() {
+        var cacheKey = 'partialinterface@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result21 = parse_extendedAttributeList();
+        var result3 = result21 !== null ? result21 : '';
+        if (result3 !== null) {
+          var result20 = parse_s();
+          var result4 = result20 !== null ? result20 : '';
+          if (result4 !== null) {
+            if (input.substr(pos, 7) === "partial") {
+              var result5 = "partial";
+              pos += 7;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"partial\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_s();
+              if (result6 !== null) {
+                if (input.substr(pos, 9) === "interface") {
+                  var result7 = "interface";
+                  pos += 9;
+                } else {
+                  var result7 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\"interface\"");
+                  }
+                }
+                if (result7 !== null) {
+                  var result8 = parse_s();
+                  if (result8 !== null) {
+                    var result9 = parse_identifier();
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        if (input.substr(pos, 1) === "{") {
+                          var result11 = "{";
+                          pos += 1;
+                        } else {
+                          var result11 = null;
+                          if (reportMatchFailures) {
+                            matchFailed("\"{\"");
+                          }
+                        }
+                        if (result11 !== null) {
+                          var result12 = parse_w();
+                          if (result12 !== null) {
+                            var result13 = [];
+                            var result19 = parse_ifMember();
+                            while (result19 !== null) {
+                              result13.push(result19);
+                              var result19 = parse_ifMember();
+                            }
+                            if (result13 !== null) {
+                              var result14 = parse_w();
+                              if (result14 !== null) {
+                                if (input.substr(pos, 1) === "}") {
+                                  var result15 = "}";
+                                  pos += 1;
+                                } else {
+                                  var result15 = null;
+                                  if (reportMatchFailures) {
+                                    matchFailed("\"}\"");
+                                  }
+                                }
+                                if (result15 !== null) {
+                                  var result16 = parse_w();
+                                  if (result16 !== null) {
+                                    if (input.substr(pos, 1) === ";") {
+                                      var result17 = ";";
+                                      pos += 1;
+                                    } else {
+                                      var result17 = null;
+                                      if (reportMatchFailures) {
+                                        matchFailed("\";\"");
+                                      }
+                                    }
+                                    if (result17 !== null) {
+                                      var result18 = parse_w();
+                                      if (result18 !== null) {
+                                        var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16, result17, result18];
+                                      } else {
+                                        var result1 = null;
+                                        pos = savedPos1;
+                                      }
+                                    } else {
+                                      var result1 = null;
+                                      pos = savedPos1;
+                                    }
+                                  } else {
+                                    var result1 = null;
+                                    pos = savedPos1;
+                                  }
+                                } else {
+                                  var result1 = null;
+                                  pos = savedPos1;
+                                }
+                              } else {
+                                var result1 = null;
+                                pos = savedPos1;
+                              }
+                            } else {
+                              var result1 = null;
+                              pos = savedPos1;
+                            }
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, name, mem) { return { type: "partialinterface", name: name, members: mem, extAttrs: extAttrs }; })(result1[0], result1[6], result1[10])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_module() {
+        var cacheKey = 'module@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result18 = parse_extendedAttributeList();
+        var result3 = result18 !== null ? result18 : '';
+        if (result3 !== null) {
+          var result17 = parse_s();
+          var result4 = result17 !== null ? result17 : '';
+          if (result4 !== null) {
+            if (input.substr(pos, 6) === "module") {
+              var result5 = "module";
+              pos += 6;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"module\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_s();
+              if (result6 !== null) {
+                var result7 = parse_identifier();
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    if (input.substr(pos, 1) === "{") {
+                      var result9 = "{";
+                      pos += 1;
+                    } else {
+                      var result9 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("\"{\"");
+                      }
+                    }
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        var result11 = parse_definitions();
+                        if (result11 !== null) {
+                          var result12 = parse_w();
+                          if (result12 !== null) {
+                            if (input.substr(pos, 1) === "}") {
+                              var result13 = "}";
+                              pos += 1;
+                            } else {
+                              var result13 = null;
+                              if (reportMatchFailures) {
+                                matchFailed("\"}\"");
+                              }
+                            }
+                            if (result13 !== null) {
+                              var result14 = parse_w();
+                              if (result14 !== null) {
+                                if (input.substr(pos, 1) === ";") {
+                                  var result15 = ";";
+                                  pos += 1;
+                                } else {
+                                  var result15 = null;
+                                  if (reportMatchFailures) {
+                                    matchFailed("\";\"");
+                                  }
+                                }
+                                if (result15 !== null) {
+                                  var result16 = parse_w();
+                                  if (result16 !== null) {
+                                    var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16];
+                                  } else {
+                                    var result1 = null;
+                                    pos = savedPos1;
+                                  }
+                                } else {
+                                  var result1 = null;
+                                  pos = savedPos1;
+                                }
+                              } else {
+                                var result1 = null;
+                                pos = savedPos1;
+                              }
+                            } else {
+                              var result1 = null;
+                              pos = savedPos1;
+                            }
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, name, defs) { return { type: "module", name: name, definitions: defs, extAttrs: extAttrs }; })(result1[0], result1[4], result1[8])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_implements() {
+        var cacheKey = 'implements@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result14 = parse_extendedAttributeList();
+        var result3 = result14 !== null ? result14 : '';
+        if (result3 !== null) {
+          var result13 = parse_s();
+          var result4 = result13 !== null ? result13 : '';
+          if (result4 !== null) {
+            var result5 = parse_ScopedName();
+            if (result5 !== null) {
+              var result6 = parse_s();
+              if (result6 !== null) {
+                if (input.substr(pos, 10) === "implements") {
+                  var result7 = "implements";
+                  pos += 10;
+                } else {
+                  var result7 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\"implements\"");
+                  }
+                }
+                if (result7 !== null) {
+                  var result8 = parse_s();
+                  if (result8 !== null) {
+                    var result9 = parse_ScopedName();
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        if (input.substr(pos, 1) === ";") {
+                          var result11 = ";";
+                          pos += 1;
+                        } else {
+                          var result11 = null;
+                          if (reportMatchFailures) {
+                            matchFailed("\";\"");
+                          }
+                        }
+                        if (result11 !== null) {
+                          var result12 = parse_w();
+                          if (result12 !== null) {
+                            var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12];
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, target, impl) { return { type: 'implements', target: target, 'implements': impl, extAttrs: extAttrs }; })(result1[0], result1[2], result1[6])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_interface() {
+        var cacheKey = 'interface@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result22 = parse_extendedAttributeList();
+        var result3 = result22 !== null ? result22 : '';
+        if (result3 !== null) {
+          var result21 = parse_s();
+          var result4 = result21 !== null ? result21 : '';
+          if (result4 !== null) {
+            if (input.substr(pos, 9) === "interface") {
+              var result5 = "interface";
+              pos += 9;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"interface\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_s();
+              if (result6 !== null) {
+                var result7 = parse_identifier();
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    var result20 = parse_ifInheritance();
+                    var result9 = result20 !== null ? result20 : '';
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        if (input.substr(pos, 1) === "{") {
+                          var result11 = "{";
+                          pos += 1;
+                        } else {
+                          var result11 = null;
+                          if (reportMatchFailures) {
+                            matchFailed("\"{\"");
+                          }
+                        }
+                        if (result11 !== null) {
+                          var result12 = parse_w();
+                          if (result12 !== null) {
+                            var result13 = [];
+                            var result19 = parse_ifMember();
+                            while (result19 !== null) {
+                              result13.push(result19);
+                              var result19 = parse_ifMember();
+                            }
+                            if (result13 !== null) {
+                              var result14 = parse_w();
+                              if (result14 !== null) {
+                                if (input.substr(pos, 1) === "}") {
+                                  var result15 = "}";
+                                  pos += 1;
+                                } else {
+                                  var result15 = null;
+                                  if (reportMatchFailures) {
+                                    matchFailed("\"}\"");
+                                  }
+                                }
+                                if (result15 !== null) {
+                                  var result16 = parse_w();
+                                  if (result16 !== null) {
+                                    if (input.substr(pos, 1) === ";") {
+                                      var result17 = ";";
+                                      pos += 1;
+                                    } else {
+                                      var result17 = null;
+                                      if (reportMatchFailures) {
+                                        matchFailed("\";\"");
+                                      }
+                                    }
+                                    if (result17 !== null) {
+                                      var result18 = parse_w();
+                                      if (result18 !== null) {
+                                        var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16, result17, result18];
+                                      } else {
+                                        var result1 = null;
+                                        pos = savedPos1;
+                                      }
+                                    } else {
+                                      var result1 = null;
+                                      pos = savedPos1;
+                                    }
+                                  } else {
+                                    var result1 = null;
+                                    pos = savedPos1;
+                                  }
+                                } else {
+                                  var result1 = null;
+                                  pos = savedPos1;
+                                }
+                              } else {
+                                var result1 = null;
+                                pos = savedPos1;
+                              }
+                            } else {
+                              var result1 = null;
+                              pos = savedPos1;
+                            }
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, name, herit, mem) { return { type: "interface", name: name, inheritance: herit, members: mem, extAttrs: extAttrs }; })(result1[0], result1[4], result1[6], result1[10])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ifInheritance() {
+        var cacheKey = 'ifInheritance@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 1) === ":") {
+          var result3 = ":";
+          pos += 1;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\":\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            var result5 = parse_ScopedNameList();
+            if (result5 !== null) {
+              var result1 = [result3, result4, result5];
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(herit) { return herit; })(result1[2])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ifMember() {
+        var cacheKey = 'ifMember@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var result4 = parse_const();
+        if (result4 !== null) {
+          var result1 = result4;
+        } else {
+          var result3 = parse_attrOrOp();
+          if (result3 !== null) {
+            var result1 = result3;
+          } else {
+            var result1 = null;;
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(mem) { return mem; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_const() {
+        var cacheKey = 'const@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result18 = parse_extendedAttributeList();
+        var result3 = result18 !== null ? result18 : '';
+        if (result3 !== null) {
+          var result17 = parse_s();
+          var result4 = result17 !== null ? result17 : '';
+          if (result4 !== null) {
+            if (input.substr(pos, 5) === "const") {
+              var result5 = "const";
+              pos += 5;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"const\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_s();
+              if (result6 !== null) {
+                var result7 = parse_type();
+                if (result7 !== null) {
+                  var result8 = parse_s();
+                  if (result8 !== null) {
+                    var result9 = parse_identifier();
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        if (input.substr(pos, 1) === "=") {
+                          var result11 = "=";
+                          pos += 1;
+                        } else {
+                          var result11 = null;
+                          if (reportMatchFailures) {
+                            matchFailed("\"=\"");
+                          }
+                        }
+                        if (result11 !== null) {
+                          var result12 = parse_w();
+                          if (result12 !== null) {
+                            var result13 = parse_constExpr();
+                            if (result13 !== null) {
+                              var result14 = parse_w();
+                              if (result14 !== null) {
+                                if (input.substr(pos, 1) === ";") {
+                                  var result15 = ";";
+                                  pos += 1;
+                                } else {
+                                  var result15 = null;
+                                  if (reportMatchFailures) {
+                                    matchFailed("\";\"");
+                                  }
+                                }
+                                if (result15 !== null) {
+                                  var result16 = parse_w();
+                                  if (result16 !== null) {
+                                    var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16];
+                                  } else {
+                                    var result1 = null;
+                                    pos = savedPos1;
+                                  }
+                                } else {
+                                  var result1 = null;
+                                  pos = savedPos1;
+                                }
+                              } else {
+                                var result1 = null;
+                                pos = savedPos1;
+                              }
+                            } else {
+                              var result1 = null;
+                              pos = savedPos1;
+                            }
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, type, name, value) { return { type: "const", extAttrs: extAttrs, idlType: type, name: name, value: value }; })(result1[0], result1[4], result1[6], result1[10])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_constExpr() {
+        var cacheKey = 'constExpr@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var result5 = parse_BooleanLiteral();
+        if (result5 !== null) {
+          var result1 = result5;
+        } else {
+          var result4 = parse_float();
+          if (result4 !== null) {
+            var result1 = result4;
+          } else {
+            var result3 = parse_integer();
+            if (result3 !== null) {
+              var result1 = result3;
+            } else {
+              var result1 = null;;
+            };
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(value) { return value; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_attrOrOp() {
+        var cacheKey = 'attrOrOp@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var result5 = parse_Stringifier();
+        if (result5 !== null) {
+          var result1 = result5;
+        } else {
+          var result4 = parse_Attribute();
+          if (result4 !== null) {
+            var result1 = result4;
+          } else {
+            var result3 = parse_Operation();
+            if (result3 !== null) {
+              var result1 = result3;
+            } else {
+              var result1 = null;;
+            };
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(ao) { return ao; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_Stringifier() {
+        var cacheKey = 'Stringifier@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 11) === "stringifier") {
+          var result3 = "stringifier";
+          pos += 11;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"stringifier\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            var result8 = parse_Attribute();
+            if (result8 !== null) {
+              var result5 = result8;
+            } else {
+              var result7 = parse_OperationRest();
+              if (result7 !== null) {
+                var result5 = result7;
+              } else {
+                if (input.substr(pos, 1) === ";") {
+                  var result6 = ";";
+                  pos += 1;
+                } else {
+                  var result6 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\";\"");
+                  }
+                }
+                if (result6 !== null) {
+                  var result5 = result6;
+                } else {
+                  var result5 = null;;
+                };
+              };
+            }
+            if (result5 !== null) {
+              var result1 = [result3, result4, result5];
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(rest) {
+                      if (rest === ";") return { type: "stringifier" };
+                      else {
+                          rest.stringifier = true;
+                          return rest;
+                      }
+                  })(result1[2])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_Attribute() {
+        var cacheKey = 'Attribute@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result23 = parse_extendedAttributeList();
+        var result3 = result23 !== null ? result23 : '';
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            var savedPos2 = pos;
+            if (input.substr(pos, 8) === "readonly") {
+              var result21 = "readonly";
+              pos += 8;
+            } else {
+              var result21 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"readonly\"");
+              }
+            }
+            if (result21 !== null) {
+              var result22 = parse_s();
+              if (result22 !== null) {
+                var result20 = [result21, result22];
+              } else {
+                var result20 = null;
+                pos = savedPos2;
+              }
+            } else {
+              var result20 = null;
+              pos = savedPos2;
+            }
+            var result5 = result20 !== null ? result20 : '';
+            if (result5 !== null) {
+              if (input.substr(pos, 9) === "attribute") {
+                var result6 = "attribute";
+                pos += 9;
+              } else {
+                var result6 = null;
+                if (reportMatchFailures) {
+                  matchFailed("\"attribute\"");
+                }
+              }
+              if (result6 !== null) {
+                var result7 = parse_s();
+                if (result7 !== null) {
+                  var result8 = parse_type();
+                  if (result8 !== null) {
+                    var result9 = parse_s();
+                    if (result9 !== null) {
+                      var result10 = parse_identifier();
+                      if (result10 !== null) {
+                        var result11 = parse_w();
+                        if (result11 !== null) {
+                          var result19 = parse_GetRaises();
+                          var result12 = result19 !== null ? result19 : '';
+                          if (result12 !== null) {
+                            var result13 = parse_w();
+                            if (result13 !== null) {
+                              var result18 = parse_SetRaises();
+                              var result14 = result18 !== null ? result18 : '';
+                              if (result14 !== null) {
+                                var result15 = parse_w();
+                                if (result15 !== null) {
+                                  if (input.substr(pos, 1) === ";") {
+                                    var result16 = ";";
+                                    pos += 1;
+                                  } else {
+                                    var result16 = null;
+                                    if (reportMatchFailures) {
+                                      matchFailed("\";\"");
+                                    }
+                                  }
+                                  if (result16 !== null) {
+                                    var result17 = parse_w();
+                                    if (result17 !== null) {
+                                      var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16, result17];
+                                    } else {
+                                      var result1 = null;
+                                      pos = savedPos1;
+                                    }
+                                  } else {
+                                    var result1 = null;
+                                    pos = savedPos1;
+                                  }
+                                } else {
+                                  var result1 = null;
+                                  pos = savedPos1;
+                                }
+                              } else {
+                                var result1 = null;
+                                pos = savedPos1;
+                              }
+                            } else {
+                              var result1 = null;
+                              pos = savedPos1;
+                            }
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, ro, type, name, gr, sr) { return { type: "attribute", extAttrs: extAttrs, idlType: type, name: name, readonly: (ro ? true : false), getraises: gr, setraises: sr }; })(result1[0], result1[2], result1[5], result1[7], result1[9], result1[11])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_GetRaises() {
+        var cacheKey = 'GetRaises@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 9) === "getraises") {
+          var result3 = "getraises";
+          pos += 9;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"getraises\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            if (input.substr(pos, 1) === "(") {
+              var result5 = "(";
+              pos += 1;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"(\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_ScopedNameList();
+              if (result6 !== null) {
+                if (input.substr(pos, 1) === ")") {
+                  var result7 = ")";
+                  pos += 1;
+                } else {
+                  var result7 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\")\"");
+                  }
+                }
+                if (result7 !== null) {
+                  var result1 = [result3, result4, result5, result6, result7];
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(list) { return list; })(result1[3])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_SetRaises() {
+        var cacheKey = 'SetRaises@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 9) === "setraises") {
+          var result3 = "setraises";
+          pos += 9;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"setraises\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            if (input.substr(pos, 1) === "(") {
+              var result5 = "(";
+              pos += 1;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"(\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_ScopedNameList();
+              if (result6 !== null) {
+                if (input.substr(pos, 1) === ")") {
+                  var result7 = ")";
+                  pos += 1;
+                } else {
+                  var result7 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\")\"");
+                  }
+                }
+                if (result7 !== null) {
+                  var result1 = [result3, result4, result5, result6, result7];
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(list) { return list; })(result1[3])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_Operation() {
+        var cacheKey = 'Operation@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result8 = parse_extendedAttributeList();
+        var result3 = result8 !== null ? result8 : '';
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            var result5 = parse_Qualifiers();
+            if (result5 !== null) {
+              var result6 = parse_w();
+              if (result6 !== null) {
+                var result7 = parse_OperationRest();
+                if (result7 !== null) {
+                  var result1 = [result3, result4, result5, result6, result7];
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, quals, rest) {
+                      for (var k in quals) rest[k] = quals[k];
+                      if (extAttrs) rest.extAttrs = extAttrs;
+                      return rest;
+                  })(result1[0], result1[2], result1[4])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_Qualifiers() {
+        var cacheKey = 'Qualifiers@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_w();
+        if (result3 !== null) {
+          if (input.substr(pos, 6) === "static") {
+            var result7 = "static";
+            pos += 6;
+          } else {
+            var result7 = null;
+            if (reportMatchFailures) {
+              matchFailed("\"static\"");
+            }
+          }
+          if (result7 !== null) {
+            var result4 = result7;
+          } else {
+            var result5 = [];
+            var result6 = parse_Special();
+            while (result6 !== null) {
+              result5.push(result6);
+              var result6 = parse_Special();
+            }
+            if (result5 !== null) {
+              var result4 = result5;
+            } else {
+              var result4 = null;;
+            };
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(quals) {   if (typeof quals == "string") return [quals];
+          		    return quals; })(result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_Special() {
+        var cacheKey = 'Special@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_w();
+        if (result3 !== null) {
+          if (input.substr(pos, 6) === "getter") {
+            var result10 = "getter";
+            pos += 6;
+          } else {
+            var result10 = null;
+            if (reportMatchFailures) {
+              matchFailed("\"getter\"");
+            }
+          }
+          if (result10 !== null) {
+            var result4 = result10;
+          } else {
+            if (input.substr(pos, 6) === "setter") {
+              var result9 = "setter";
+              pos += 6;
+            } else {
+              var result9 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"setter\"");
+              }
+            }
+            if (result9 !== null) {
+              var result4 = result9;
+            } else {
+              if (input.substr(pos, 7) === "creator") {
+                var result8 = "creator";
+                pos += 7;
+              } else {
+                var result8 = null;
+                if (reportMatchFailures) {
+                  matchFailed("\"creator\"");
+                }
+              }
+              if (result8 !== null) {
+                var result4 = result8;
+              } else {
+                if (input.substr(pos, 7) === "deleter") {
+                  var result7 = "deleter";
+                  pos += 7;
+                } else {
+                  var result7 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\"deleter\"");
+                  }
+                }
+                if (result7 !== null) {
+                  var result4 = result7;
+                } else {
+                  if (input.substr(pos, 12) === "legacycaller") {
+                    var result6 = "legacycaller";
+                    pos += 12;
+                  } else {
+                    var result6 = null;
+                    if (reportMatchFailures) {
+                      matchFailed("\"legacycaller\"");
+                    }
+                  }
+                  if (result6 !== null) {
+                    var result4 = result6;
+                  } else {
+                    var result4 = null;;
+                  };
+                };
+              };
+            };
+          }
+          if (result4 !== null) {
+            var result5 = parse_w();
+            if (result5 !== null) {
+              var result1 = [result3, result4, result5];
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(spe) { return spe; })(result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_OperationRest() {
+        var cacheKey = 'OperationRest@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_ReturnType();
+        if (result3 !== null) {
+          var result4 = parse_s();
+          if (result4 !== null) {
+            var result19 = parse_identifier();
+            var result5 = result19 !== null ? result19 : '';
+            if (result5 !== null) {
+              var result6 = parse_w();
+              if (result6 !== null) {
+                if (input.substr(pos, 1) === "(") {
+                  var result7 = "(";
+                  pos += 1;
+                } else {
+                  var result7 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\"(\"");
+                  }
+                }
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    var result18 = parse_Arguments();
+                    var result9 = result18 !== null ? result18 : '';
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        if (input.substr(pos, 1) === ")") {
+                          var result11 = ")";
+                          pos += 1;
+                        } else {
+                          var result11 = null;
+                          if (reportMatchFailures) {
+                            matchFailed("\")\"");
+                          }
+                        }
+                        if (result11 !== null) {
+                          var result12 = parse_w();
+                          if (result12 !== null) {
+                            var result17 = parse_Raises();
+                            var result13 = result17 !== null ? result17 : '';
+                            if (result13 !== null) {
+                              var result14 = parse_w();
+                              if (result14 !== null) {
+                                if (input.substr(pos, 1) === ";") {
+                                  var result15 = ";";
+                                  pos += 1;
+                                } else {
+                                  var result15 = null;
+                                  if (reportMatchFailures) {
+                                    matchFailed("\";\"");
+                                  }
+                                }
+                                if (result15 !== null) {
+                                  var result16 = parse_w();
+                                  if (result16 !== null) {
+                                    var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16];
+                                  } else {
+                                    var result1 = null;
+                                    pos = savedPos1;
+                                  }
+                                } else {
+                                  var result1 = null;
+                                  pos = savedPos1;
+                                }
+                              } else {
+                                var result1 = null;
+                                pos = savedPos1;
+                              }
+                            } else {
+                              var result1 = null;
+                              pos = savedPos1;
+                            }
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(ret, name, args, exc) { return { type: "operation", idlType: ret, name: name, arguments: (args ? args : []), raises: exc }; })(result1[0], result1[2], result1[6], result1[10])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_Arguments() {
+        var cacheKey = 'Arguments@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_Argument();
+        if (result3 !== null) {
+          var result4 = [];
+          var result5 = parse_ArgumentsRest();
+          while (result5 !== null) {
+            result4.push(result5);
+            var result5 = parse_ArgumentsRest();
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(first, others) {   var ret = [first];
+                      for (var i = 0, n = others.length; i < n; i++) { ret.push(others[i]); }
+                      return ret; })(result1[0], result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ArgumentsRest() {
+        var cacheKey = 'ArgumentsRest@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_w();
+        if (result3 !== null) {
+          if (input.substr(pos, 1) === ",") {
+            var result4 = ",";
+            pos += 1;
+          } else {
+            var result4 = null;
+            if (reportMatchFailures) {
+              matchFailed("\",\"");
+            }
+          }
+          if (result4 !== null) {
+            var result5 = parse_w();
+            if (result5 !== null) {
+              var result6 = parse_Argument();
+              if (result6 !== null) {
+                var result1 = [result3, result4, result5, result6];
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(rest) { return rest; })(result1[3])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_Argument() {
+        var cacheKey = 'Argument@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result16 = parse_extendedAttributeList();
+        var result3 = result16 !== null ? result16 : '';
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            if (input.substr(pos, 2) === "in") {
+              var result15 = "in";
+              pos += 2;
+            } else {
+              var result15 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"in\"");
+              }
+            }
+            var result5 = result15 !== null ? result15 : '';
+            if (result5 !== null) {
+              var result6 = parse_w();
+              if (result6 !== null) {
+                if (input.substr(pos, 8) === "optional") {
+                  var result14 = "optional";
+                  pos += 8;
+                } else {
+                  var result14 = null;
+                  if (reportMatchFailures) {
+                    matchFailed("\"optional\"");
+                  }
+                }
+                var result7 = result14 !== null ? result14 : '';
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    var result9 = parse_type();
+                    if (result9 !== null) {
+                      if (input.substr(pos, 3) === "...") {
+                        var result13 = "...";
+                        pos += 3;
+                      } else {
+                        var result13 = null;
+                        if (reportMatchFailures) {
+                          matchFailed("\"...\"");
+                        }
+                      }
+                      var result10 = result13 !== null ? result13 : '';
+                      if (result10 !== null) {
+                        var result11 = parse_s();
+                        if (result11 !== null) {
+                          var result12 = parse_identifier();
+                          if (result12 !== null) {
+                            var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12];
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, opt, type, ell, name) { return { name: name, type: type, variadic: (ell ? true : false), optional: (opt ? true : false), extAttrs: extAttrs }; })(result1[0], result1[4], result1[6], result1[7], result1[9])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_Raises() {
+        var cacheKey = 'Raises@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 6) === "raises") {
+          var result3 = "raises";
+          pos += 6;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"raises\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_s();
+          if (result4 !== null) {
+            if (input.substr(pos, 1) === "(") {
+              var result5 = "(";
+              pos += 1;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"(\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_w();
+              if (result6 !== null) {
+                var result7 = parse_ScopedNameList();
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    if (input.substr(pos, 1) === ")") {
+                      var result9 = ")";
+                      pos += 1;
+                    } else {
+                      var result9 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("\")\"");
+                      }
+                    }
+                    if (result9 !== null) {
+                      var result1 = [result3, result4, result5, result6, result7, result8, result9];
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(list) { return list; })(result1[4])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_dictionary() {
+        var cacheKey = 'dictionary@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 10) === "dictionary") {
+          var result3 = "dictionary";
+          pos += 10;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"dictionary\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_s();
+          if (result4 !== null) {
+            var result5 = parse_identifier();
+            if (result5 !== null) {
+              var result6 = parse_w();
+              if (result6 !== null) {
+                var result18 = parse_ifInheritance();
+                var result7 = result18 !== null ? result18 : '';
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    if (input.substr(pos, 1) === "{") {
+                      var result9 = "{";
+                      pos += 1;
+                    } else {
+                      var result9 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("\"{\"");
+                      }
+                    }
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        var result11 = [];
+                        var result17 = parse_dictionaryMember();
+                        while (result17 !== null) {
+                          result11.push(result17);
+                          var result17 = parse_dictionaryMember();
+                        }
+                        if (result11 !== null) {
+                          var result12 = parse_w();
+                          if (result12 !== null) {
+                            if (input.substr(pos, 1) === "}") {
+                              var result13 = "}";
+                              pos += 1;
+                            } else {
+                              var result13 = null;
+                              if (reportMatchFailures) {
+                                matchFailed("\"}\"");
+                              }
+                            }
+                            if (result13 !== null) {
+                              var result14 = parse_w();
+                              if (result14 !== null) {
+                                if (input.substr(pos, 1) === ";") {
+                                  var result15 = ";";
+                                  pos += 1;
+                                } else {
+                                  var result15 = null;
+                                  if (reportMatchFailures) {
+                                    matchFailed("\";\"");
+                                  }
+                                }
+                                if (result15 !== null) {
+                                  var result16 = parse_w();
+                                  if (result16 !== null) {
+                                    var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16];
+                                  } else {
+                                    var result1 = null;
+                                    pos = savedPos1;
+                                  }
+                                } else {
+                                  var result1 = null;
+                                  pos = savedPos1;
+                                }
+                              } else {
+                                var result1 = null;
+                                pos = savedPos1;
+                              }
+                            } else {
+                              var result1 = null;
+                              pos = savedPos1;
+                            }
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(name, superclass, members) {
+                          return { 
+                              type: "dictionary",
+                              name: name,
+                              inheritance: superclass,
+                              members: members
+                          };
+                      })(result1[2], result1[4], result1[8])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_dictionaryMember() {
+        var cacheKey = 'dictionaryMember@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result14 = parse_extendedAttributeList();
+        var result3 = result14 !== null ? result14 : '';
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            var result5 = parse_type();
+            if (result5 !== null) {
+              var result6 = parse_s();
+              if (result6 !== null) {
+                var result7 = parse_identifier();
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    var result13 = parse_defaultValue();
+                    var result9 = result13 !== null ? result13 : '';
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        if (input.substr(pos, 1) === ";") {
+                          var result11 = ";";
+                          pos += 1;
+                        } else {
+                          var result11 = null;
+                          if (reportMatchFailures) {
+                            matchFailed("\";\"");
+                          }
+                        }
+                        if (result11 !== null) {
+                          var result12 = parse_w();
+                          if (result12 !== null) {
+                            var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12];
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, type, name, defaultValue) {
+                       return {
+                           type: type,
+                           name: name,
+                           defaultValue: defaultValue
+                       };
+                   })(result1[0], result1[2], result1[4], result1[6])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_defaultValue() {
+        var cacheKey = 'defaultValue@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 1) === "=") {
+          var result3 = "=";
+          pos += 1;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"=\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            var result5 = parse_constExpr();
+            if (result5 !== null) {
+              var result1 = [result3, result4, result5];
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(value) { return value; })(result1[2])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_typedef() {
+        var cacheKey = 'typedef@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        if (input.substr(pos, 7) === "typedef") {
+          var result3 = "typedef";
+          pos += 7;
+        } else {
+          var result3 = null;
+          if (reportMatchFailures) {
+            matchFailed("\"typedef\"");
+          }
+        }
+        if (result3 !== null) {
+          var result4 = parse_s();
+          if (result4 !== null) {
+            var result5 = parse_type();
+            if (result5 !== null) {
+              var result6 = parse_s();
+              if (result6 !== null) {
+                var result7 = parse_identifier();
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    if (input.substr(pos, 1) === ";") {
+                      var result9 = ";";
+                      pos += 1;
+                    } else {
+                      var result9 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("\";\"");
+                      }
+                    }
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        var result1 = [result3, result4, result5, result6, result7, result8, result9, result10];
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(type, name) { return { type: 'typedef', name: name, idlType: type }; })(result1[2], result1[4])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_exception() {
+        var cacheKey = 'exception@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result18 = parse_extendedAttributeList();
+        var result3 = result18 !== null ? result18 : '';
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            if (input.substr(pos, 9) === "exception") {
+              var result5 = "exception";
+              pos += 9;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"exception\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_s();
+              if (result6 !== null) {
+                var result7 = parse_identifier();
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    if (input.substr(pos, 1) === "{") {
+                      var result9 = "{";
+                      pos += 1;
+                    } else {
+                      var result9 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("\"{\"");
+                      }
+                    }
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        var result11 = [];
+                        var result17 = parse_exMember();
+                        while (result17 !== null) {
+                          result11.push(result17);
+                          var result17 = parse_exMember();
+                        }
+                        if (result11 !== null) {
+                          var result12 = parse_w();
+                          if (result12 !== null) {
+                            if (input.substr(pos, 1) === "}") {
+                              var result13 = "}";
+                              pos += 1;
+                            } else {
+                              var result13 = null;
+                              if (reportMatchFailures) {
+                                matchFailed("\"}\"");
+                              }
+                            }
+                            if (result13 !== null) {
+                              var result14 = parse_w();
+                              if (result14 !== null) {
+                                if (input.substr(pos, 1) === ";") {
+                                  var result15 = ";";
+                                  pos += 1;
+                                } else {
+                                  var result15 = null;
+                                  if (reportMatchFailures) {
+                                    matchFailed("\";\"");
+                                  }
+                                }
+                                if (result15 !== null) {
+                                  var result16 = parse_w();
+                                  if (result16 !== null) {
+                                    var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16];
+                                  } else {
+                                    var result1 = null;
+                                    pos = savedPos1;
+                                  }
+                                } else {
+                                  var result1 = null;
+                                  pos = savedPos1;
+                                }
+                              } else {
+                                var result1 = null;
+                                pos = savedPos1;
+                              }
+                            } else {
+                              var result1 = null;
+                              pos = savedPos1;
+                            }
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, name, mem) { return { type: 'exception', name: name, members: mem, extAttrs: extAttrs }; })(result1[0], result1[4], result1[8])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_exMember() {
+        var cacheKey = 'exMember@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var result4 = parse_const();
+        if (result4 !== null) {
+          var result1 = result4;
+        } else {
+          var result3 = parse_field();
+          if (result3 !== null) {
+            var result1 = result3;
+          } else {
+            var result1 = null;;
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(mem) { return mem; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_field() {
+        var cacheKey = 'field@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result12 = parse_extendedAttributeList();
+        var result3 = result12 !== null ? result12 : '';
+        if (result3 !== null) {
+          var result11 = parse_s();
+          var result4 = result11 !== null ? result11 : '';
+          if (result4 !== null) {
+            var result5 = parse_type();
+            if (result5 !== null) {
+              var result6 = parse_s();
+              if (result6 !== null) {
+                var result7 = parse_identifier();
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    if (input.substr(pos, 1) === ";") {
+                      var result9 = ";";
+                      pos += 1;
+                    } else {
+                      var result9 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("\";\"");
+                      }
+                    }
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        var result1 = [result3, result4, result5, result6, result7, result8, result9, result10];
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(extAttrs, type, name) { return { type: "field", extAttrs: extAttrs, idlType: type, name: name }; })(result1[0], result1[2], result1[4])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_extendedAttributeList() {
+        var cacheKey = 'extendedAttributeList@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_w();
+        if (result3 !== null) {
+          if (input.substr(pos, 1) === "[") {
+            var result4 = "[";
+            pos += 1;
+          } else {
+            var result4 = null;
+            if (reportMatchFailures) {
+              matchFailed("\"[\"");
+            }
+          }
+          if (result4 !== null) {
+            var result5 = parse_w();
+            if (result5 !== null) {
+              var result6 = parse_ExtAttrs();
+              if (result6 !== null) {
+                var result7 = parse_w();
+                if (result7 !== null) {
+                  if (input.substr(pos, 1) === "]") {
+                    var result8 = "]";
+                    pos += 1;
+                  } else {
+                    var result8 = null;
+                    if (reportMatchFailures) {
+                      matchFailed("\"]\"");
+                    }
+                  }
+                  if (result8 !== null) {
+                    var result9 = parse_w();
+                    if (result9 !== null) {
+                      var result1 = [result3, result4, result5, result6, result7, result8, result9];
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(ea) { return ea; })(result1[3])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ExtAttrs() {
+        var cacheKey = 'ExtAttrs@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_ExtAttr();
+        if (result3 !== null) {
+          var result4 = [];
+          var result5 = parse_ExtAttrsRest();
+          while (result5 !== null) {
+            result4.push(result5);
+            var result5 = parse_ExtAttrsRest();
+          }
+          if (result4 !== null) {
+            var result1 = [result3, result4];
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(first, others) {   var ret = [first];
+                      for (var i = 0, n = others.length; i < n; i++) { ret.push(others[i]); }
+                      return ret; })(result1[0], result1[1])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ExtAttrsRest() {
+        var cacheKey = 'ExtAttrsRest@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_w();
+        if (result3 !== null) {
+          if (input.substr(pos, 1) === ",") {
+            var result4 = ",";
+            pos += 1;
+          } else {
+            var result4 = null;
+            if (reportMatchFailures) {
+              matchFailed("\",\"");
+            }
+          }
+          if (result4 !== null) {
+            var result5 = parse_w();
+            if (result5 !== null) {
+              var result6 = parse_ExtAttr();
+              if (result6 !== null) {
+                var result1 = [result3, result4, result5, result6];
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(rest) { return rest; })(result1[3])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ExtAttr() {
+        var cacheKey = 'ExtAttr@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var result6 = parse_ExtAttrArgList();
+        if (result6 !== null) {
+          var result1 = result6;
+        } else {
+          var result5 = parse_ExtAttrNamedArgList();
+          if (result5 !== null) {
+            var result1 = result5;
+          } else {
+            var result4 = parse_ExtAttrNameValue();
+            if (result4 !== null) {
+              var result1 = result4;
+            } else {
+              var result3 = parse_ExtAttrNoArg();
+              if (result3 !== null) {
+                var result1 = result3;
+              } else {
+                var result1 = null;;
+              };
+            };
+          };
+        }
+        var result2 = result1 !== null
+          ? (function(ea) { return ea; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ExtAttrNoArg() {
+        var cacheKey = 'ExtAttrNoArg@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var result1 = parse_identifier();
+        var result2 = result1 !== null
+          ? (function(name) {return { name: name }; })(result1)
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ExtAttrNameValue() {
+        var cacheKey = 'ExtAttrNameValue@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_identifier();
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            if (input.substr(pos, 1) === "=") {
+              var result5 = "=";
+              pos += 1;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"=\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_w();
+              if (result6 !== null) {
+                var result7 = parse_ScopedName();
+                if (result7 !== null) {
+                  var result1 = [result3, result4, result5, result6, result7];
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(name, value) {return { name: name, value: value }; })(result1[0], result1[4])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ExtAttrNamedArgList() {
+        var cacheKey = 'ExtAttrNamedArgList@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_identifier();
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            if (input.substr(pos, 1) === "=") {
+              var result5 = "=";
+              pos += 1;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"=\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_w();
+              if (result6 !== null) {
+                var result7 = parse_identifier();
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    if (input.substr(pos, 1) === "(") {
+                      var result9 = "(";
+                      pos += 1;
+                    } else {
+                      var result9 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("\"(\"");
+                      }
+                    }
+                    if (result9 !== null) {
+                      var result10 = parse_w();
+                      if (result10 !== null) {
+                        var result14 = parse_Arguments();
+                        var result11 = result14 !== null ? result14 : '';
+                        if (result11 !== null) {
+                          var result12 = parse_w();
+                          if (result12 !== null) {
+                            if (input.substr(pos, 1) === ")") {
+                              var result13 = ")";
+                              pos += 1;
+                            } else {
+                              var result13 = null;
+                              if (reportMatchFailures) {
+                                matchFailed("\")\"");
+                              }
+                            }
+                            if (result13 !== null) {
+                              var result1 = [result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13];
+                            } else {
+                              var result1 = null;
+                              pos = savedPos1;
+                            }
+                          } else {
+                            var result1 = null;
+                            pos = savedPos1;
+                          }
+                        } else {
+                          var result1 = null;
+                          pos = savedPos1;
+                        }
+                      } else {
+                        var result1 = null;
+                        pos = savedPos1;
+                      }
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(name, value, args) {return { name: name, value: value, arguments: args }; })(result1[0], result1[4], result1[8])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function parse_ExtAttrArgList() {
+        var cacheKey = 'ExtAttrArgList@' + pos;
+        var cachedResult = cache[cacheKey];
+        if (cachedResult) {
+          pos = cachedResult.nextPos;
+          return cachedResult.result;
+        }
+        
+        
+        var savedPos0 = pos;
+        var savedPos1 = pos;
+        var result3 = parse_identifier();
+        if (result3 !== null) {
+          var result4 = parse_w();
+          if (result4 !== null) {
+            if (input.substr(pos, 1) === "(") {
+              var result5 = "(";
+              pos += 1;
+            } else {
+              var result5 = null;
+              if (reportMatchFailures) {
+                matchFailed("\"(\"");
+              }
+            }
+            if (result5 !== null) {
+              var result6 = parse_w();
+              if (result6 !== null) {
+                var result10 = parse_Arguments();
+                var result7 = result10 !== null ? result10 : '';
+                if (result7 !== null) {
+                  var result8 = parse_w();
+                  if (result8 !== null) {
+                    if (input.substr(pos, 1) === ")") {
+                      var result9 = ")";
+                      pos += 1;
+                    } else {
+                      var result9 = null;
+                      if (reportMatchFailures) {
+                        matchFailed("\")\"");
+                      }
+                    }
+                    if (result9 !== null) {
+                      var result1 = [result3, result4, result5, result6, result7, result8, result9];
+                    } else {
+                      var result1 = null;
+                      pos = savedPos1;
+                    }
+                  } else {
+                    var result1 = null;
+                    pos = savedPos1;
+                  }
+                } else {
+                  var result1 = null;
+                  pos = savedPos1;
+                }
+              } else {
+                var result1 = null;
+                pos = savedPos1;
+              }
+            } else {
+              var result1 = null;
+              pos = savedPos1;
+            }
+          } else {
+            var result1 = null;
+            pos = savedPos1;
+          }
+        } else {
+          var result1 = null;
+          pos = savedPos1;
+        }
+        var result2 = result1 !== null
+          ? (function(name, args) {return { name: name, arguments: args }; })(result1[0], result1[4])
+          : null;
+        if (result2 !== null) {
+          var result0 = result2;
+        } else {
+          var result0 = null;
+          pos = savedPos0;
+        }
+        
+        
+        
+        cache[cacheKey] = {
+          nextPos: pos,
+          result:  result0
+        };
+        return result0;
+      }
+      
+      function buildErrorMessage() {
+        function buildExpected(failuresExpected) {
+          failuresExpected.sort();
+          
+          var lastFailure = null;
+          var failuresExpectedUnique = [];
+          for (var i = 0; i < failuresExpected.length; i++) {
+            if (failuresExpected[i] !== lastFailure) {
+              failuresExpectedUnique.push(failuresExpected[i]);
+              lastFailure = failuresExpected[i];
+            }
+          }
+          
+          switch (failuresExpectedUnique.length) {
+            case 0:
+              return 'end of input';
+            case 1:
+              return failuresExpectedUnique[0];
+            default:
+              return failuresExpectedUnique.slice(0, failuresExpectedUnique.length - 1).join(', ')
+                + ' or '
+                + failuresExpectedUnique[failuresExpectedUnique.length - 1];
+          }
+        }
+        
+        var expected = buildExpected(rightmostMatchFailuresExpected);
+        var actualPos = Math.max(pos, rightmostMatchFailuresPos);
+        var actual = actualPos < input.length
+          ? quote(input.charAt(actualPos))
+          : 'end of input';
+        
+        return 'Expected ' + expected + ' but ' + actual + ' found.';
+      }
+      
+      function computeErrorPosition() {
+        /*
+         * The first idea was to use |String.split| to break the input up to the
+         * error position along newlines and derive the line and column from
+         * there. However IE's |split| implementation is so broken that it was
+         * enough to prevent it.
+         */
+        
+        var line = 1;
+        var column = 1;
+        var seenCR = false;
+        
+        for (var i = 0; i <  rightmostMatchFailuresPos; i++) {
+          var ch = input.charAt(i);
+          if (ch === '\n') {
+            if (!seenCR) { line++; }
+            column = 1;
+            seenCR = false;
+          } else if (ch === '\r' | ch === '\u2028' || ch === '\u2029') {
+            line++;
+            column = 1;
+            seenCR = true;
+          } else {
+            column++;
+            seenCR = false;
+          }
+        }
+        
+        return { line: line, column: column };
+      }
+      
+      
+      
+      var result = parseFunctions[startRule]();
+      
+      /*
+       * The parser is now in one of the following three states:
+       *
+       * 1. The parser successfully parsed the whole input.
+       *
+       *    - |result !== null|
+       *    - |pos === input.length|
+       *    - |rightmostMatchFailuresExpected| may or may not contain something
+       *
+       * 2. The parser successfully parsed only a part of the input.
+       *
+       *    - |result !== null|
+       *    - |pos < input.length|
+       *    - |rightmostMatchFailuresExpected| may or may not contain something
+       *
+       * 3. The parser did not successfully parse any part of the input.
+       *
+       *   - |result === null|
+       *   - |pos === 0|
+       *   - |rightmostMatchFailuresExpected| contains at least one failure
+       *
+       * All code following this comment (including called functions) must
+       * handle these states.
+       */
+      if (result === null || pos !== input.length) {
+        var errorPosition = computeErrorPosition();
+        throw new this.SyntaxError(
+          buildErrorMessage(),
+          errorPosition.line,
+          errorPosition.column
+        );
+      }
+      
+      return result;
+    },
+    
+    /* Returns the parser source code. */
+    toSource: function() { return this._source; }
+  };
+  
+  /* Thrown when a parser encounters a syntax error. */
+  
+  result.SyntaxError = function(message, line, column) {
+    this.name = 'SyntaxError';
+    this.message = message;
+    this.line = line;
+    this.column = column;
+  };
+  
+  result.SyntaxError.prototype = Error.prototype;
+  
+  return result;
+})();
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/failures.txt
@@ -0,0 +1,2 @@
+html
+webapps
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html.json
@@ -0,0 +1,2 @@
+{
+}
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html.mk
@@ -0,0 +1,3 @@
+DIRS += \
+  html/tests/submission/Mozilla \
+  $(NULL)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html.txt
@@ -0,0 +1,2 @@
+https://dvcs.w3.org/hg/html|html
+tests/submission/Mozilla
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html/tests/submission/Mozilla/Makefile.in
@@ -0,0 +1,31 @@
+# THIS FILE IS AUTOGENERATED - DO NOT EDIT
+
+DEPTH = ../../../../../../../..
+
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = dom/tests/mochitest/w3c/html/tests/submission/Mozilla
+
+DIRS = \
+  $(NULL)
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_TESTS = \
+  test_body-onload.html \
+  test_pageload-image.html \
+  test_pageload-video.html \
+  test_script-for-onload.html \
+  test_window-onerror-parse-error.html \
+  test_window-onerror-runtime-error.html \
+  test_window-onerror-runtime-error-throw.html \
+  $(NULL)
+
+_TESTS += \
+  nested-document-write-external.js \
+  $(NULL)
+
+libs:: $(_TESTS)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html/tests/submission/Mozilla/nested-document-write-external.js
@@ -0,0 +1,1 @@
+document.write("w"); document.write("o");
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html/tests/submission/Mozilla/test_body-onload.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>HTMLBodyElement.onload</title>
+<link rel="author" title="Boris Zbarsky" href="mailto:bzbarsky@mit.edu">
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="http://www.whatwg.org/html/#handler-window-onload">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test("body.onload should set the window.onload handler")
+window.onload = t.step_func(function() {
+  assert_unreached("This handler should be overwritten.")
+})
+var b = document.createElement("body")
+b.onload = t.step_func(function(e) {
+  assert_equals(e.currentTarget, window,
+                "The event should be fired at the window.")
+  t.done()
+})
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html/tests/submission/Mozilla/test_pageload-image.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Media documents: image</title>
+  <link rel="author" title="Michael Ventnor" href="mailto:mventnor@mozilla.com">
+  <link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+  <link rel="help" href="http://www.whatwg.org/html/#read-media">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+
+<script>
+  var t = async_test("The document for a standalone media file should have one child in the body.");
+
+  function frameLoaded() {
+    var testframe = document.getElementById('testframe');
+    var testframeChildren = testframe.contentDocument.body.childNodes;
+    assert_equals(testframeChildren.length, 1, "Body of image document has 1 child");
+    assert_equals(testframeChildren[0].nodeName, "IMG", "Only child of body must be an <img> element");
+    assert_equals(testframeChildren[0].namespaceURI, "http://www.w3.org/1999/xhtml",
+                  "Only child of body must be an HTML element");
+    t.done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+  <iframe id="testframe" onload="t.step(frameLoaded)"
+   src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oMFgQGMyFwHucAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC"></iframe>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html/tests/submission/Mozilla/test_pageload-video.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Media documents: video</title>
+  <link rel="author" title="Michael Ventnor" href="mailto:mventnor@mozilla.com">
+  <link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+  <link rel="help" href="http://www.whatwg.org/html/#read-media">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+
+<script>
+  var t = async_test("The document for a standalone media file should have one child in the body.");
+
+  function frameLoaded() {
+    var testframe = document.getElementById('testframe');
+    var testframeChildren = testframe.contentDocument.body.childNodes;
+    assert_equals(testframeChildren.length, 1, "Body of image document has 1 child");
+    assert_equals(testframeChildren[0].nodeName, "VIDEO", "Only child of body must be an <video> element");
+    assert_equals(testframeChildren[0].namespaceURI, "http://www.w3.org/1999/xhtml",
+                  "Only child of body must be an HTML element");
+    t.done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+  <iframe id="testframe" onload="t.step(frameLoaded)"
+   src="data:video/webm,"></iframe>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html/tests/submission/Mozilla/test_script-for-onload.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Script for and onload attributes</title>
+<link rel="author" title="Matheus Kerschbaum" href="mailto:matjk7@gmail.com">
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="http://www.whatwg.org/html/#prepare-a-script">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test("Script for and onload attributes");
+</script>
+<script for=" window " event=" onload() ">
+var foo = "bar";
+</script>
+<script for="object" event="handler">
+// This script should fail to run
+foo = "baz";
+t.step(function() { assert_unreached("This script should fail to run."); });
+</script>
+<script>
+t.step(function() { assert_equals(foo, "bar", "Correct script was executed."); });
+t.done();
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html/tests/submission/Mozilla/test_window-onerror-parse-error.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<html>
+ <head>
+  <title>window.onerror: parse errors</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <!--
+
+    In http://dev.w3.org/html5/spec/webappapis.html#creating-scripts ,
+    step 3 describes parsing the script, and step 5 says:
+      # Otherwise, report the error using the onerror event handler of
+      # the script's global object. If the error is still not handled
+      # after this, then the error may be reported to the user.
+    which links to
+    http://dev.w3.org/html5/spec/webappapis.html#report-the-error ,
+    which describes what to do when onerror is a Function.
+
+    -->
+ </head>
+ <body>
+
+  <div id="log"></div>
+  <script>
+    var error_count = 0;
+    window.onerror = function(msg, url, lineno) {
+      ++error_count;
+      test(function() {assert_equals(url, window.location.href)},
+           "correct url passed to window.onerror");
+      test(function() {assert_equals(lineno, 33)},
+           "correct line number passed to window.onerror");
+    };
+  </script>
+  <script>This script does not parse correctly.</script>
+  <script>
+  test(function() {assert_equals(error_count, 1)},
+       "correct number of calls to window.onerror");
+  </script>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html/tests/submission/Mozilla/test_window-onerror-runtime-error-throw.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <head>
+  <title>window.onerror: runtime scripterrors</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <!--
+
+    http://www.w3.org/TR/html5/webappapis.html#runtime-script-errors
+    says what to do for uncaught runtime script errors, and just below
+    describes what to do when onerror is a Function.
+
+    -->
+ </head>
+ <body>
+
+  <div id="log"></div>
+  <script>
+    var error_count = 0;
+    window.onerror = function(msg, url, lineno) {
+      ++error_count;
+    };
+  </script>
+  <script>
+  try {
+    // This error is caught, so it should NOT trigger onerror.
+    throw "foo";
+  } catch (ex) {
+  }
+  // This error is NOT caught, so it should trigger onerror.
+  throw "bar";
+  </script>
+  <script>
+  test(function() {assert_equals(error_count, 1)},
+       "correct number of calls to window.onerror");
+  </script>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/html/tests/submission/Mozilla/test_window-onerror-runtime-error.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<html>
+ <head>
+  <title>window.onerror: runtime scripterrors</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <!--
+
+    http://www.w3.org/TR/html5/webappapis.html#runtime-script-errors
+    says what to do for uncaught runtime script errors, and just below
+    describes what to do when onerror is a Function.
+
+    -->
+ </head>
+ <body>
+
+  <div id="log"></div>
+  <script>
+    var error_count = 0;
+    window.onerror = function(msg, url, lineno) {
+      ++error_count;
+      test(function() {assert_equals(url, window.location.href)},
+           "correct url passed to window.onerror");
+      test(function() {assert_equals(lineno, 35)},
+           "correct line number passed to window.onerror");
+    };
+  </script>
+  <script>
+  try {
+    // This error is caught, so it should NOT trigger onerror.
+    window.nonexistentproperty.oops();
+  } catch (ex) {
+  }
+  // This error is NOT caught, so it should trigger onerror.
+  window.nonexistentproperty.oops();
+  </script>
+  <script>
+  test(function() {assert_equals(error_count, 1)},
+       "correct number of calls to window.onerror");
+  </script>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/w3c/idlharness.js
@@ -0,0 +1,1487 @@
+/*
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+*/
+
+/*
+ * This file automatically generates browser tests for WebIDL interfaces, using
+ * the testharness.js framework.  To use, first include the following:
+ *
+ *   <script src=/resources/testharness.js></script>
+ *   <script src=/resources/testharnessreport.js></script>
+ *   <script src=/resources/WebIDLParser.js></script>
+ *   <script src=/resources/idlharness.js></script>
+ *
+ * Then you'll need some type of IDLs.  Here's some script that can be run on a
+ * spec written in HTML, which will grab all the elements with class="idl",
+ * concatenate them, and replace the body so you can copy-paste:
+ *
+     var s = "";
+     [].forEach.call(document.getElementsByClassName("idl"), function(idl) {
+       //https://www.w3.org/Bugs/Public/show_bug.cgi?id=14914
+       if (!idl.classList.contains("extract"))
+       {
+         s += idl.textContent + "\n\n";
+       }
+     });
+     document.body.innerHTML = '<pre></pre>';
+     document.body.firstChild.textContent = s;
+ *
+ * (TODO: write this in Python or something so that it can be done from the
+ * command line instead.)
+ *
+ * Once you have that, put it in your script somehow.  The easiest way is to
+ * embed it literally in an HTML file with <script type=text/plain> or similar,
+ * so that you don't have to do any escaping.  Another possibility is to put it
+ * in a separate .idl file that's fetched via XHR or similar.  Sample usage:
+ *
+ *   var idl_array = new IdlArray();
+ *   idl_array.add_untested_idls("interface Node { readonly attribute DOMString nodeName; };");
+ *   idl_array.add_idls("interface Document : Node { readonly attribute DOMString URL; };");
+ *   idl_array.add_objects({Document: ["document"]});
+ *   idl_array.test();
+ *
+ * This tests that window.Document exists and meets all the requirements of
+ * WebIDL.  It also tests that window.document (the result of evaluating the
+ * string "document") has URL and nodeName properties that behave as they
+ * should, and otherwise meets WebIDL's requirements for an object whose
+ * primary interface is Document.  It does not test that window.Node exists,
+ * which is what you want if the Node interface is already tested in some other
+ * specification's suite and your specification only extends or refers to it.
+ * Of course, each IDL string can define many different things, and calls to
+ * add_objects() can register many different objects for different interfaces:
+ * this is a very simple example.
+ *
+ * TODO: Write assert_writable, assert_enumerable, assert_configurable and
+ * their inverses, and use those instead of just checking
+ * getOwnPropertyDescriptor.
+ *
+ * == Public methods of IdlArray ==
+ *
+ * IdlArray objects can be obtained with new IdlArray().  Anything not
+ * documented in this section should be considered an implementation detail,
+ * and outside callers should not use it.
+ *
+ * add_idls(idl_string):
+ *   Parses idl_string (throwing on parse error) and adds the results to the
+ *   IdlArray.  All the definitions will be tested when you run test().  If
+ *   some of the definitions refer to other definitions, those must be present
+ *   too.  For instance, if idl_string says that Document inherits from Node,
+ *   the Node interface must also have been provided in some call to add_idls()
+ *   or add_untested_idls().
+ *
+ * add_untested_idls(idl_string):
+ *   Like add_idls(), but the definitions will not be tested.  If an untested
+ *   interface is added and then extended with a tested partial interface, the
+ *   members of the partial interface will still be tested.  Also, all the
+ *   members will still be tested for objects added with add_objects(), because
+ *   you probably want to test that (for instance) window.document has all the
+ *   properties from Node, not just Document, even if the Node interface itself
+ *   is tested in a different test suite.
+ *
+ * add_objects(dict):
+ *   dict should be an object whose keys are the names of interfaces or
+ *   exceptions, and whose values are arrays of strings.  When an interface or
+ *   exception is tested, every string registered for it with add_objects()
+ *   will be evaluated, and tests will be run on the result to verify that it
+ *   correctly implements that interface or exception.  This is the only way to
+ *   test anything about [NoInterfaceObject] interfaces, and there are many
+ *   tests that can't be run on any interface without an object to fiddle with.
+ *
+ *   The interface has to be the *primary* interface of all the objects
+ *   provided.  For example, don't pass {Node: ["document"]}, but rather
+ *   {Document: ["document"]}.  Assuming the Document interface was declared to
+ *   inherit from Node, this will automatically test that document implements
+ *   the Node interface too.
+ *
+ *   Warning: methods will be called on any provided objects, in a manner that
+ *   WebIDL requires be safe.  For instance, if a method has mandatory
+ *   arguments, the test suite will try calling it with too few arguments to
+ *   see if it throws an exception.  If an implementation incorrectly runs the
+ *   function instead of throwing, this might have side effects, possibly even
+ *   preventing the test suite from running correctly.
+ *
+ * prevent_multiple_testing(name):
+ *   This is a niche method for use in case you're testing many objects that
+ *   implement the same interfaces, and don't want to retest the same
+ *   interfaces every single time.  For instance, HTML defines many interfaces
+ *   that all inherit from HTMLElement, so the HTML test suite has something
+ *   like
+ *     .add_objects({
+ *         HTMLHtmlElement: ['document.documentElement'],
+ *         HTMLHeadElement: ['document.head'],
+ *         HTMLBodyElement: ['document.body'],
+ *         ...
+ *     })
+ *   and so on for dozens of element types.  This would mean that it would
+ *   retest that each and every one of those elements implements HTMLElement,
+ *   Element, and Node, which would be thousands of basically redundant tests.
+ *   The test suite therefore calls prevent_multiple_testing("HTMLElement").
+ *   This means that once one object has been tested to implement HTMLElement
+ *   and its ancestors, no other object will be.  Thus in the example code
+ *   above, the harness would test that document.documentElement correctly
+ *   implements HTMLHtmlElement, HTMLElement, Element, and Node; but
+ *   document.head would only be tested for HTMLHeadElement, and so on for
+ *   further objects.
+ *
+ * test():
+ *   Run all tests.  This should be called after you've called all other
+ *   methods to add IDLs and objects.
+ */
+"use strict";
+(function(){
+/// IdlArray ///
+//Entry point
+window.IdlArray = function()
+//@{
+{
+    this.members = {};
+    this.objects = {};
+    // When adding multiple collections of IDLs one at a time, an earlier one
+    // might contain a partial interface or implements statement that depends
+    // on a later one.  Save these up and handle them right before we run
+    // tests.
+    this.partials = [];
+    this.implements = {};
+}
+
+//@}
+IdlArray.prototype.add_idls = function(raw_idls)
+//@{
+{
+    this.internal_add_idls(WebIDLParser.parse(raw_idls));
+};
+
+//@}
+IdlArray.prototype.add_untested_idls = function(raw_idls)
+//@{
+{
+    var parsed_idls = WebIDLParser.parse(raw_idls);
+    for (var i = 0; i < parsed_idls.length; i++)
+    {
+        parsed_idls[i].untested = true;
+        if ("members" in parsed_idls[i])
+        {
+            for (var j = 0; j < parsed_idls[i].members.length; j++)
+            {
+                parsed_idls[i].members[j].untested = true;
+            }
+        }
+    }
+    this.internal_add_idls(parsed_idls);
+}
+
+//@}
+IdlArray.prototype.internal_add_idls = function(parsed_idls)
+//@{
+{
+    parsed_idls.forEach(function(parsed_idl)
+    {
+        if (parsed_idl.type == "partialinterface")
+        {
+            this.partials.push(parsed_idl);
+            return;
+        }
+
+        if (parsed_idl.type == "implements")
+        {
+            if (!(parsed_idl.target in this.implements))
+            {
+                this.implements[parsed_idl.target] = [];
+            }
+            this.implements[parsed_idl.target].push(parsed_idl.implements);
+            return;
+        }
+
+        parsed_idl.array = this;
+        if (parsed_idl.name in this.members)
+        {
+            throw "Duplicate identifier " + parsed_idl.name;
+        }
+        switch(parsed_idl.type)
+        {
+        case "interface":
+            this.members[parsed_idl.name] = new IdlInterface(parsed_idl);
+            break;
+
+        case "exception":
+            this.members[parsed_idl.name] = new IdlException(parsed_idl);
+            break;
+
+        case "dictionary":
+            //Nothing to test, but we need the dictionary info around for type
+            //checks
+            this.members[parsed_idl.name] = new IdlDictionary(parsed_idl);
+            break;
+
+        case "typedef":
+            //TODO
+            break;
+
+        default:
+            throw parsed_idl.name + ": " + parsed_idl.type + " not yet supported";
+        }
+    }.bind(this));
+}
+
+//@}
+IdlArray.prototype.add_objects = function(dict)
+//@{
+{
+    for (var k in dict)
+    {
+        if (k in this.objects)
+        {
+            this.objects[k] = this.objects[k].concat(dict[k]);
+        }
+        else
+        {
+            this.objects[k] = dict[k];
+        }
+    }
+}
+
+//@}
+IdlArray.prototype.prevent_multiple_testing = function(name)
+//@{
+{
+    this.members[name].prevent_multiple_testing = true;
+}
+
+//@}
+IdlArray.prototype.recursively_get_implements = function(interface_name)
+//@{
+{
+    var ret = this.implements[interface_name];
+    if (ret === undefined)
+    {
+        return [];
+    }
+    for (var i = 0; i < this.implements[interface_name].length; i++)
+    {
+        ret = ret.concat(this.recursively_get_implements(ret[i]));
+        if (ret.indexOf(ret[i]) != ret.lastIndexOf(ret[i]))
+        {
+            throw "Circular implements statements involving " + ret[i];
+        }
+    }
+    return ret;
+}
+
+//@}
+IdlArray.prototype.test = function()
+//@{
+{
+    this.partials.forEach(function(parsed_idl)
+    {
+        if (!(parsed_idl.name in this.members)
+        || !(this.members[parsed_idl.name] instanceof IdlInterface))
+        {
+            throw "Partial interface " + parsed_idl.name + " with no original interface";
+        }
+        if (parsed_idl.extAttrs)
+        {
+            parsed_idl.extAttrs.forEach(function(extAttr)
+            {
+                this.members[parsed_idl.name].extAttrs.push(extAttr);
+            }.bind(this));
+        }
+        parsed_idl.members.forEach(function(member)
+        {
+            this.members[parsed_idl.name].members.push(new IdlInterfaceMember(member));
+        }.bind(this));
+    }.bind(this));
+    this.partials = [];
+
+    for (var lhs in this.implements)
+    {
+        this.recursively_get_implements(lhs).forEach(function(rhs)
+        {
+            if (!(lhs in this.members)
+            || !(this.members[lhs] instanceof IdlInterface)
+            || !(rhs in this.members)
+            || !(this.members[rhs] instanceof IdlInterface))
+            {
+                throw lhs + " implements " + rhs + ", but one is undefined or not an interface";
+            }
+            this.members[rhs].members.forEach(function(member)
+            {
+                this.members[lhs].members.push(new IdlInterfaceMember(member));
+            }.bind(this));
+        }.bind(this));
+    }
+    this.implements = {};
+
+    for (var name in this.members)
+    {
+        this.members[name].test();
+        if (name in this.objects)
+        {
+            this.objects[name].forEach(function(str)
+            {
+                this.members[name].test_object(str);
+            }.bind(this));
+        }
+    }
+};
+
+//@}
+IdlArray.prototype.assert_type_is = function(value, type)
+//@{
+{
+    if (type.idlType == "any")
+    {
+        //No assertions to make
+        return;
+    }
+
+    if (type.nullable && value === null)
+    {
+        //This is fine
+        return;
+    }
+
+    if (type.array)
+    {
+        //TODO: not supported yet
+        return;
+    }
+
+    if (type.sequence)
+    {
+        assert_true(Array.isArray(value), "is not array");
+        if (!type.idlType.length)
+        {
+            return;
+        }
+        type = type.idlType[0];
+    }
+    else
+    {
+        type = type.idlType;
+    }
+
+    switch(type)
+    {
+        case "void":
+            assert_equals(value, undefined);
+            return;
+
+        case "boolean":
+            assert_equals(typeof value, "boolean");
+            return;
+
+        case "byte":
+            assert_equals(typeof value, "number");
+            assert_equals(value, Math.floor(value), "not an integer");
+            assert_true(-128 <= value && value <= 127, "byte " + value + " not in range [-128, 127]");
+            return;
+
+        case "octet":
+            assert_equals(typeof value, "number");
+            assert_equals(value, Math.floor(value), "not an integer");
+            assert_true(0 <= value && value <= 255, "octet " + value + " not in range [0, 255]");
+            return;
+
+        case "short":
+            assert_equals(typeof value, "number");
+            assert_equals(value, Math.floor(value), "not an integer");
+            assert_true(-32768 <= value && value <= 32767, "short " + value + " not in range [-32768, 32767]");
+            return;
+
+        case "unsigned short":
+            assert_equals(typeof value, "number");
+            assert_equals(value, Math.floor(value), "not an integer");
+            assert_true(0 <= value && value <= 65535, "unsigned short " + value + " not in range [0, 65535]");
+            return;
+
+        case "long":
+            assert_equals(typeof value, "number");
+            assert_equals(value, Math.floor(value), "not an integer");
+            assert_true(-2147483648 <= value && value <= 2147483647, "long " + value + " not in range [-2147483648, 2147483647]");
+            return;
+
+        case "unsigned long":
+            assert_equals(typeof value, "number");
+            assert_equals(value, Math.floor(value), "not an integer");
+            assert_true(0 <= value && value <= 4294967295, "unsigned long " + value + " not in range [0, 4294967295]");
+            return;
+
+        case "long long":
+            assert_equals(typeof value, "number");
+            return;
+
+        case "unsigned long long":
+            assert_equals(typeof value, "number");
+            assert_true(0 <= value, "unsigned long long is negative");
+            return;
+
+        case "float":
+        case "double":
+            //TODO: distinguish these cases
+            assert_equals(typeof value, "number");
+            return;
+
+        case "DOMString":
+            assert_equals(typeof value, "string");
+            return;
+
+        case "object":
+            assert_true(typeof value == "object" || typeof value == "function", "wrong type: not object or function");
+            return;
+    }
+
+    if (!(type in this.members))
+    {
+        throw "Unrecognized type " + type;
+    }
+
+    if (this.members[type] instanceof IdlInterface)
+    {
+        //We don't want to run the full
+        //IdlInterface.prototype.test_instance_of, because that could result in
+        //an infinite loop.  TODO: This means we don't have tests for
+        //NoInterfaceObject interfaces, and we also can't test objects that
+        //come from another window.
+        assert_true(typeof value == "object" || typeof value == "function", "wrong type: not object or function");
+        if (value instanceof Object
+        && !this.members[type].has_extended_attribute("NoInterfaceObject")
+        && type in window)
+        {
+            assert_true(value instanceof window[type], "not instanceof " + type);
+        }
+    }
+    else if (this.members[type] instanceof IdlDictionary)
+    {
+        //TODO: Test when we actually have something to test this on
+    }
+    else
+    {
+        throw "Type " + type + " isn't an interface or dictionary";
+    }
+};
+//@}
+
+/// IdlObject ///
+function IdlObject() {}
+IdlObject.prototype.has_extended_attribute = function(name)
+//@{
+{
+    return this.extAttrs.some(function(o)
+    {
+        return o.name == name;
+    });
+};
+
+//@}
+IdlObject.prototype.test = function() {};
+
+/// IdlDictionary ///
+//Used for IdlArray.prototype.assert_type_is
+function IdlDictionary(obj)
+//@{
+{
+    this.name = obj.name;
+    this.members = obj.members ? obj.members : [];
+    this.inheritance = obj.inheritance ? obj.inheritance: [];
+}
+
+//@}
+IdlDictionary.prototype = Object.create(IdlObject.prototype);
+
+/// IdlException ///
+function IdlException(obj)
+//@{
+{
+    this.name = obj.name;
+    this.array = obj.array;
+    this.untested = obj.untested;
+    this.extAttrs = obj.extAttrs ? obj.extAttrs : [];
+    this.members = obj.members ? obj.members.map(function(m){return new IdlInterfaceMember(m)}) : [];
+    this.inheritance = obj.inheritance ? obj.inheritance : [];
+}
+
+//@}
+IdlException.prototype = Object.create(IdlObject.prototype);
+IdlException.prototype.test = function()
+//@{
+{
+    // Note: largely copy-pasted from IdlInterface, but then, so is the spec
+    // text.
+    if (this.has_extended_attribute("NoInterfaceObject"))
+    {
+        //No tests to do without an instance
+        return;
+    }
+
+    if (!this.untested)
+    {
+        this.test_self();
+    }
+    this.test_members();
+}
+
+//@}
+IdlException.prototype.test_self = function()
+//@{
+{
+    test(function()
+    {
+        //"For every exception that is not declared with the
+        //[NoInterfaceObject] extended attribute, a corresponding property must
+        //exist on the exception’s relevant namespace object. The name of the
+        //property is the identifier of the exception, and its value is an
+        //object called the exception interface object, which provides access
+        //to any constants that have been associated with the exception. The
+        //property has the attributes { [[Writable]]: true, [[Enumerable]]:
+        //false, [[Configurable]]: true }."
+        assert_own_property(window, this.name,
+                            "window does not have own property " + format_value(this.name));
+        var desc = Object.getOwnPropertyDescriptor(window, this.name);
+        assert_false("get" in desc, "window's property " + format_value(this.name) + " has getter");
+        assert_false("set" in desc, "window's property " + format_value(this.name) + " has setter");
+        assert_true(desc.writable, "window's property " + format_value(this.name) + " is not writable");
+        assert_false(desc.enumerable, "window's property " + format_value(this.name) + " is enumerable");
+        assert_true(desc.configurable, "window's property " + format_value(this.name) + " is not configurable");
+
+        //"The exception interface object for a given exception must be a
+        //function object."
+        //"If an object is defined to be a function object, then it has
+        //characteristics as follows:"
+        //"Its [[Prototype]] internal property is the Function prototype
+        //object."
+        //Note: This doesn't match browsers as of December 2011, see
+        //http://www.w3.org/Bugs/Public/show_bug.cgi?id=14813
+        assert_true(Function.prototype.isPrototypeOf(window[this.name]),
+                    "prototype of window's property " + format_value(this.name) + " is not Function.prototype");
+        //"Its [[Get]] internal property is set as described in ECMA-262
+        //section 15.3.5.4."
+        //Not much to test for this.
+        //"Its [[Construct]] internal property is set as described in ECMA-262
+        //section 13.2.2."
+        //Tested below.
+        //"Its [[HasInstance]] internal property is set as described in
+        //ECMA-262 section 15.3.5.3, unless otherwise specified."
+        //TODO
+        //"Its [[Class]] internal property is “Function”."
+        //String() and {}.toString.call() should be equivalent, since nothing
+        //defines a stringifier.
+        assert_equals({}.toString.call(window[this.name]), "[object Function]",
+                      "{}.toString.call(" + this.name + ")");
+        assert_equals(String(window[this.name]), "[object Function]",
+                      "String(" + this.name + ")");
+
+        //TODO: Test 4.9.1.1. Exception interface object [[Call]] method (which
+        //does not match browsers: //http://www.w3.org/Bugs/Public/show_bug.cgi?id=14885)
+    }.bind(this), this.name + " exception: existence and properties of exception interface object");
+
+    test(function()
+    {
+        assert_own_property(window, this.name,
+                            "window does not have own property " + format_value(this.name));
+
+        //"The exception interface object must also have a property named
+        //“prototype” with attributes { [[Writable]]: false, [[Enumerable]]:
+        //false, [[Configurable]]: false } whose value is an object called the
+        //exception interface prototype object. This object also provides
+        //access to the constants that are declared on the exception."
+        assert_own_property(window[this.name], "prototype",
+                            'exception "' + this.name + '" does not have own property "prototype"');
+        var desc = Object.getOwnPropertyDescriptor(window[this.name], "prototype");
+        assert_false("get" in desc, this.name + ".prototype has getter");
+        assert_false("set" in desc, this.name + ".prototype has setter");
+        assert_false(desc.writable, this.name + ".prototype is writable");
+        assert_false(desc.enumerable, this.name + ".prototype is enumerable");
+        assert_false(desc.configurable, this.name + ".prototype is configurable");
+
+        //"The exception interface prototype object for a given exception must
+        //have an internal [[Prototype]] property whose value is as follows:
+        //
+        //"If the exception is declared to inherit from another exception, then
+        //the value of the internal [[Prototype]] property is the exception
+        //interface prototype object for the inherited exception.
+        //"Otherwise, the exception is not declared to inherit from another
+        //exception. The value of the internal [[Prototype]] property is the
+        //Error prototype object ([ECMA-262], section 15.11.3.1)."
+        //Note: This doesn't match browsers as of December 2011, see
+        //https://www.w3.org/Bugs/Public/show_bug.cgi?id=14887.
+        var inherit_exception = this.inheritance.length ? this.inheritance[0] : "Error";
+        assert_own_property(window, inherit_exception,
+                            'should inherit from ' + inherit_exception + ', but window has no such property');
+        assert_own_property(window[inherit_exception], "prototype",
+                            'should inherit from ' + inherit_exception + ', but that object has no "prototype" property');
+        assert_true(window[inherit_exception].prototype.isPrototypeOf(window[this.name].prototype),
+                    'prototype of ' + this.name + '.prototype is not ' + inherit_exception + '.prototype');
+
+        //"The class string of an exception interface prototype object is the
+        //concatenation of the exception’s identifier and the string
+        //“Prototype”."
+        //String() and {}.toString.call() should be equivalent, since nothing
+        //defines a stringifier.
+        assert_equals({}.toString.call(window[this.name].prototype), "[object " + this.name + "Prototype]",
+                      "{}.toString.call(" + this.name + ")");
+        assert_equals(String(window[this.name].prototype), "[object " + this.name + "Prototype]",
+                      "String(" + this.name + ")");
+    }.bind(this), this.name + " exception: existence and properties of exception interface prototype object");
+
+    test(function()
+    {
+        assert_own_property(window, this.name,
+                            "window does not have own property " + format_value(this.name));
+        assert_own_property(window[this.name], "prototype",
+                            'interface "' + this.name + '" does not have own property "prototype"');
+
+        //"There must be a property named “name” on the exception interface
+        //prototype object with attributes { [[Writable]]: true,
+        //[[Enumerable]]: false, [[Configurable]]: true } and whose value is
+        //the identifier of the exception."
+        assert_own_property(window[this.name].prototype, "name",
+                'prototype object does not have own property "name"');
+        var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "name");
+        assert_false("get" in desc, this.name + ".prototype.name has getter");
+        assert_false("set" in desc, this.name + ".prototype.name has setter");
+        assert_true(desc.writable, this.name + ".prototype.name is not writable");
+        assert_false(desc.enumerable, this.name + ".prototype.name is enumerable");
+        assert_true(desc.configurable, this.name + ".prototype.name is not configurable");
+        assert_equals(desc.value, this.name, this.name + ".prototype.name has incorrect value");
+    }.bind(this), this.name + " exception: existence and properties of exception interface prototype object's \"name\" property");
+
+    test(function()
+    {
+        assert_own_property(window, this.name,
+                            "window does not have own property " + format_value(this.name));
+        assert_own_property(window[this.name], "prototype",
+                            'interface "' + this.name + '" does not have own property "prototype"');
+
+        //"If the [NoInterfaceObject] extended attribute was not specified on
+        //the exception, then there must also be a property named “constructor”
+        //on the exception interface prototype object with attributes {
+        //[[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }
+        //and whose value is a reference to the exception interface object for
+        //the exception."
+        assert_own_property(window[this.name].prototype, "constructor",
+                            this.name + '.prototype does not have own property "constructor"');
+        var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "constructor");
+        assert_false("get" in desc, this.name + ".prototype.constructor has getter");
+        assert_false("set" in desc, this.name + ".prototype.constructor has setter");
+        assert_true(desc.writable, this.name + ".prototype.constructor is not writable");
+        assert_false(desc.enumerable, this.name + ".prototype.constructor is enumerable");
+        assert_true(desc.configurable, this.name + ".prototype.constructor in not configurable");
+        assert_equals(window[this.name].prototype.constructor, window[this.name],
+                      this.name + '.prototype.constructor is not the same object as ' + this.name);
+    }.bind(this), this.name + " exception: existence and properties of exception interface prototype object's \"constructor\" property");
+}
+
+//@}
+IdlException.prototype.test_members = function()
+//@{
+{
+    for (var i = 0; i < this.members.length; i++)
+    {
+        var member = this.members[i];
+        if (member.untested)
+        {
+            continue;
+        }
+        if (member.type == "const" && member.name != "prototype")
+        {
+            test(function()
+            {
+                assert_own_property(window, this.name,
+                                    "window does not have own property " + format_value(this.name));
+
+                //"For each constant defined on the exception, there must be a
+                //corresponding property on the exception interface object, if
+                //it exists, if the identifier of the constant is not
+                //“prototype”."
+                assert_own_property(window[this.name], member.name);
+                //"The value of the property is the ECMAScript value that is
+                //equivalent to the constant’s IDL value, according to the
+                //rules in section 4.2 above."
+                assert_equals(window[this.name][member.name], eval(member.value),
+                              "property has wrong value");
+                //"The property has attributes { [[Writable]]: false,
+                //[[Enumerable]]: true, [[Configurable]]: false }."
+                var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
+                assert_false("get" in desc, "property has getter");
+                assert_false("set" in desc, "property has setter");
+                assert_false(desc.writable, "property is writable");
+                assert_true(desc.enumerable, "property is not enumerable");
+                assert_false(desc.configurable, "property is configurable");
+            }.bind(this), this.name + " exception: constant " + member.name + " on exception interface object");
+            //"In addition, a property with the same characteristics must
+            //exist on the exception interface prototype object."
+            test(function()
+            {
+                assert_own_property(window, this.name,
+                                    "window does not have own property " + format_value(this.name));
+                assert_own_property(window[this.name], "prototype",
+                                    'exception "' + this.name + '" does not have own property "prototype"');
+
+                assert_own_property(window[this.name].prototype, member.name);
+                assert_equals(window[this.name].prototype[member.name], eval(member.value),
+                              "property has wrong value");
+                var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, member.name);
+                assert_false("get" in desc, "property has getter");
+                assert_false("set" in desc, "property has setter");
+                assert_false(desc.writable, "property is writable");
+                assert_true(desc.enumerable, "property is not enumerable");
+                assert_false(desc.configurable, "property is configurable");
+            }.bind(this), this.name + " exception: constant " + member.name + " on exception interface prototype object");
+        }
+        else if (member.type == "field")
+        {
+            test(function()
+            {
+                assert_own_property(window, this.name,
+                                    "window does not have own property " + format_value(this.name));
+                assert_own_property(window[this.name], "prototype",
+                                    'exception "' + this.name + '" does not have own property "prototype"');
+
+                //"For each exception field, there must be a corresponding
+                //property on the exception interface prototype object, whose
+                //characteristics are as follows:
+                //"The name of the property is the identifier of the exception
+                //field."
+                assert_own_property(window[this.name].prototype, member.name);
+                //"The property has attributes { [[Get]]: G, [[Enumerable]]:
+                //true, [[Configurable]]: true }, where G is the exception
+                //field getter, defined below."
+                var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, member.name);
+                assert_false("value" in desc, "property descriptor has value but is supposed to be accessor");
+                assert_false("writable" in desc, 'property descriptor has "writable" field but is supposed to be accessor');
+                //TODO: ES5 doesn't seem to say whether desc should have a .set
+                //property.
+                assert_true(desc.enumerable, "property is not enumerable");
+                assert_true(desc.configurable, "property is not configurable");
+                //"The exception field getter is a Function object whose