changeset 34:afca92a2e72e

enumeration is now supported on wrappers via JSNewEnumerateOp.
author Atul Varma <varmaa@toolness.com>
date Mon, 22 Jun 2009 15:33:18 -0700
parents cb058fac14fa
children 5899faf625d4
files tcb.js wrapper.cpp
diffstat 2 files changed, 63 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/tcb.js	Mon Jun 22 14:39:04 2009 -0700
+++ b/tcb.js	Mon Jun 22 15:33:18 2009 -0700
@@ -149,8 +149,10 @@
     return wrappee == other;
   },
 
-  enumerate: function() {
-    throw new Error("Enumeration is not implemented.");
+  enumerate: function(wrappee, wrapper) {
+    // TODO: Is this secure?
+    for (name in wrappee)
+      yield name;
   },
 
   iteratorObject: function(wrappee, wrapper, keysOnly) {
@@ -205,6 +207,11 @@
    print("module.foo() is " + module.foo());
    })();
 
+for (name in module)
+  print(name);
+
+print("enumerate is " + enumerate(module));
+
 // Some unit tests.
 
 var wrapper = {};
--- a/wrapper.cpp	Mon Jun 22 14:39:04 2009 -0700
+++ b/wrapper.cpp	Mon Jun 22 15:33:18 2009 -0700
@@ -36,6 +36,8 @@
 
 #include "wrapper.h"
 
+#include "string.h"
+
 // Reserved slot ID for the resolver (meta) object
 #define SLOT_RESOLVER 0
 
@@ -83,14 +85,52 @@
 }
 
 static JSBool
-enumerate(JSContext *cx, JSObject *obj)
-{
-  if (resolverHasMethod(cx, obj, "enumerate")) {
+enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
+          jsval *statep, jsid *idp)
+{  
+  switch (enum_op) {
+  case JSENUMERATE_INIT:
+    if (resolverHasMethod(cx, obj, "enumerate")) {
+      if (!delegateToResolver(cx, obj, "enumerate", 0, NULL, statep))
+        return JS_FALSE;
+      if (!JSVAL_IS_OBJECT(*statep)) {
+        JS_ReportError(cx, "Expected enumerate() to return an iterator.");
+        return JS_FALSE;
+      }
+      *idp = JSVAL_ZERO;
+      // TODO: Root the enumeration iterator?
+      return JS_TRUE;
+    }
+    // TODO: Default behavior?
+    JS_ReportError(cx, "Enumeration is not implemented on this object.");
+    return JS_FALSE;
+  case JSENUMERATE_NEXT:
     jsval rval;
-    if (!delegateToResolver(cx, obj, "enumerate", 0, NULL, &rval))
+    JSObject *iterator = JSVAL_TO_OBJECT(*statep);
+    if (!JS_CallFunctionName(cx, iterator, "next", 0, NULL, &rval)) {
+      if (JS_IsExceptionPending(cx)) {
+        jsval exception;
+        if (!JS_GetPendingException(cx, &exception))
+          return JS_FALSE;
+        if (!JSVAL_IS_OBJECT(exception))
+          return JS_FALSE;
+        JSClass *klass = JS_GET_CLASS(cx, JSVAL_TO_OBJECT(exception));
+        if (klass && strcmp(klass->name, "StopIteration") == 0) {
+          JS_ClearPendingException(cx);
+          *statep = JSVAL_NULL;
+          // TODO: Unroot the enumeration iterator?
+          return JS_TRUE;
+        }
+      }
       return JS_FALSE;
+    }
+    if (!JS_ValueToId(cx, rval, idp))
+      return JS_FALSE;
+    return JS_TRUE;
+  case JSENUMERATE_DESTROY:
+    // TODO: Unroot the enumeration iterator?
+    return JS_TRUE;
   }
-  return JS_EnumerateStub(cx, obj);
 }
 
 static JSBool
@@ -293,15 +333,15 @@
   // JSClass (JSExtendedClass.base) initialization
   { "FlexibleWrapper",
     JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
-    JSCLASS_HAS_RESERVED_SLOTS(2),
-    addProperty,        delProperty,
-    getProperty,        setProperty,
-    enumerate,          (JSResolveOp)resolve,
-    convert,            JS_FinalizeStub,
-    NULL,               checkAccess,
-    call,               construct,
-    NULL,               NULL,
-    NULL,               NULL
+    JSCLASS_NEW_ENUMERATE | JSCLASS_HAS_RESERVED_SLOTS(2),
+    addProperty,              delProperty,
+    getProperty,              setProperty,
+    (JSEnumerateOp)enumerate, (JSResolveOp)resolve,
+    convert,                  JS_FinalizeStub,
+    NULL,                     checkAccess,
+    call,                     construct,
+    NULL,                     NULL,
+    NULL,                     NULL
   },
   // JSExtendedClass initialization
   equality,