📄 jsiter.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sw=4 et tw=78: * * ***** 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/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * JavaScript iterators. */#include "jsstddef.h"#include <string.h> /* for memcpy */#include "jstypes.h"#include "jsutil.h"#include "jsarena.h"#include "jsapi.h"#include "jsarray.h"#include "jsatom.h"#include "jsbool.h"#include "jscntxt.h"#include "jsconfig.h"#include "jsexn.h"#include "jsfun.h"#include "jsgc.h"#include "jsinterp.h"#include "jsiter.h"#include "jslock.h"#include "jsnum.h"#include "jsobj.h"#include "jsopcode.h"#include "jsscope.h"#include "jsscript.h"#if JS_HAS_XML_SUPPORT#include "jsxml.h"#endifextern const char js_throw_str[]; /* from jsscan.h */#define JSSLOT_ITER_STATE (JSSLOT_PRIVATE)#define JSSLOT_ITER_FLAGS (JSSLOT_PRIVATE + 1)#if JSSLOT_ITER_FLAGS >= JS_INITIAL_NSLOTS#error JS_INITIAL_NSLOTS must be greater than JSSLOT_ITER_FLAGS.#endif/* * Shared code to close iterator's state either through an explicit call or * when GC detects that the iterator is no longer reachable. */voidjs_CloseIteratorState(JSContext *cx, JSObject *iterobj){ jsval *slots; jsval state, parent; JSObject *iterable; JS_ASSERT(JS_InstanceOf(cx, iterobj, &js_IteratorClass, NULL)); slots = iterobj->slots; /* Avoid double work if js_CloseNativeIterator was called on obj. */ state = slots[JSSLOT_ITER_STATE]; if (JSVAL_IS_NULL(state)) return; /* Protect against failure to fully initialize obj. */ parent = slots[JSSLOT_PARENT]; if (!JSVAL_IS_PRIMITIVE(parent)) { iterable = JSVAL_TO_OBJECT(parent);#if JS_HAS_XML_SUPPORT if ((JSVAL_TO_INT(slots[JSSLOT_ITER_FLAGS]) & JSITER_FOREACH) && OBJECT_IS_XML(cx, iterable)) { ((JSXMLObjectOps *) iterable->map->ops)-> enumerateValues(cx, iterable, JSENUMERATE_DESTROY, &state, NULL, NULL); } else#endif OBJ_ENUMERATE(cx, iterable, JSENUMERATE_DESTROY, &state, NULL); } slots[JSSLOT_ITER_STATE] = JSVAL_NULL;}JSClass js_IteratorClass = { "Iterator", JSCLASS_HAS_RESERVED_SLOTS(2) | /* slots for state and flags */ JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS};static JSBoolInitNativeIterator(JSContext *cx, JSObject *iterobj, JSObject *obj, uintN flags){ jsval state; JSBool ok; JS_ASSERT(JSVAL_TO_PRIVATE(iterobj->slots[JSSLOT_CLASS]) == &js_IteratorClass); /* Initialize iterobj in case of enumerate hook failure. */ iterobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj); iterobj->slots[JSSLOT_ITER_STATE] = JSVAL_NULL; iterobj->slots[JSSLOT_ITER_FLAGS] = INT_TO_JSVAL(flags); if (!js_RegisterCloseableIterator(cx, iterobj)) return JS_FALSE; if (!obj) return JS_TRUE; ok =#if JS_HAS_XML_SUPPORT ((flags & JSITER_FOREACH) && OBJECT_IS_XML(cx, obj)) ? ((JSXMLObjectOps *) obj->map->ops)-> enumerateValues(cx, obj, JSENUMERATE_INIT, &state, NULL, NULL) :#endif OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &state, NULL); if (!ok) return JS_FALSE; iterobj->slots[JSSLOT_ITER_STATE] = state; if (flags & JSITER_ENUMERATE) { /* * The enumerating iterator needs the original object to suppress * enumeration of deleted or shadowed prototype properties. Since the * enumerator never escapes to scripts, we use the prototype slot to * store the original object. */ JS_ASSERT(obj != iterobj); iterobj->slots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(obj); } return JS_TRUE;}static JSBoolIterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval){ JSBool keyonly; uintN flags; JSObject *obj; keyonly = JS_FALSE; if (!js_ValueToBoolean(cx, argv[1], &keyonly)) return JS_FALSE; flags = keyonly ? 0 : JSITER_FOREACH; if (cx->fp->flags & JSFRAME_CONSTRUCTING) { /* XXX work around old valueOf call hidden beneath js_ValueToObject */ if (!JSVAL_IS_PRIMITIVE(argv[0])) { obj = JSVAL_TO_OBJECT(argv[0]); } else { obj = js_ValueToNonNullObject(cx, argv[0]); if (!obj) return JS_FALSE; argv[0] = OBJECT_TO_JSVAL(obj); } return InitNativeIterator(cx, iterobj, obj, flags); } *rval = argv[0]; return js_ValueToIterator(cx, flags, rval);}static JSBoolNewKeyValuePair(JSContext *cx, jsid key, jsval val, jsval *rval){ jsval vec[2]; JSTempValueRooter tvr; JSObject *aobj; vec[0] = ID_TO_VALUE(key); vec[1] = val; JS_PUSH_TEMP_ROOT(cx, 2, vec, &tvr); aobj = js_NewArrayObject(cx, 2, vec); *rval = OBJECT_TO_JSVAL(aobj); JS_POP_TEMP_ROOT(cx, &tvr); return aobj != NULL;}static JSBoolIteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval){ JSObject *iterable; jsval state; uintN flags; JSBool foreach, ok; jsid id; JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_IteratorClass); iterable = OBJ_GET_PARENT(cx, obj); JS_ASSERT(iterable); state = OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_STATE); if (JSVAL_IS_NULL(state)) goto stop; flags = JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_FLAGS)); JS_ASSERT(!(flags & JSITER_ENUMERATE)); foreach = (flags & JSITER_FOREACH) != 0; ok =#if JS_HAS_XML_SUPPORT (foreach && OBJECT_IS_XML(cx, iterable)) ? ((JSXMLObjectOps *) iterable->map->ops)-> enumerateValues(cx, iterable, JSENUMERATE_NEXT, &state, &id, rval) :#endif OBJ_ENUMERATE(cx, iterable, JSENUMERATE_NEXT, &state, &id); if (!ok) return JS_FALSE; OBJ_SET_SLOT(cx, obj, JSSLOT_ITER_STATE, state); if (JSVAL_IS_NULL(state)) goto stop; if (foreach) {#if JS_HAS_XML_SUPPORT if (!OBJECT_IS_XML(cx, iterable) && !OBJ_GET_PROPERTY(cx, iterable, id, rval)) { return JS_FALSE; }#endif if (!NewKeyValuePair(cx, id, *rval, rval)) return JS_FALSE; } else { *rval = ID_TO_VALUE(id); } return JS_TRUE; stop: JS_ASSERT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_STATE) == JSVAL_NULL); *rval = JSVAL_HOLE; return JS_TRUE;}static JSBooljs_ThrowStopIteration(JSContext *cx, JSObject *obj){ jsval v; JS_ASSERT(!JS_IsExceptionPending(cx)); if (js_FindClassObject(cx, NULL, INT_TO_JSID(JSProto_StopIteration), &v)) JS_SetPendingException(cx, v); return JS_FALSE;}static JSBooliterator_next(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ if (!JS_InstanceOf(cx, obj, &js_IteratorClass, argv)) return JS_FALSE; if (!IteratorNextImpl(cx, obj, rval)) return JS_FALSE; if (*rval == JSVAL_HOLE) { *rval = JSVAL_NULL; js_ThrowStopIteration(cx, obj); return JS_FALSE; } return JS_TRUE;}static JSBooliterator_self(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ *rval = OBJECT_TO_JSVAL(obj); return JS_TRUE;}static JSFunctionSpec iterator_methods[] = { {js_iterator_str, iterator_self, 0,JSPROP_READONLY|JSPROP_PERMANENT,0}, {js_next_str, iterator_next, 0,JSPROP_READONLY|JSPROP_PERMANENT,0}, {0,0,0,0,0}};uintNjs_GetNativeIteratorFlags(JSContext *cx, JSObject *iterobj){ if (OBJ_GET_CLASS(cx, iterobj) != &js_IteratorClass) return 0; return JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_FLAGS));}voidjs_CloseNativeIterator(JSContext *cx, JSObject *iterobj){ uintN flags; /* * If this iterator is not an instance of the native default iterator * class, leave it to be GC'ed. */ if (!JS_InstanceOf(cx, iterobj, &js_IteratorClass, NULL)) return; /* * If this iterator was not created by js_ValueToIterator called from the * for-in loop code in js_Interpret, leave it to be GC'ed. */ flags = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_FLAGS)); if (!(flags & JSITER_ENUMERATE)) return; js_CloseIteratorState(cx, iterobj);}/* * Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists. * Otherwise construct the defualt iterator. */JSBooljs_ValueToIterator(JSContext *cx, uintN flags, jsval *vp){ JSObject *obj; JSTempValueRooter tvr; const JSAtom *atom; JSBool ok; JSObject *iterobj; jsval arg; JSString *str; JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | JSITER_FOREACH |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -