mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
b7796202d5
--HG-- extra : rebase_source : ffdd302bbad433d6a67e7b7ff8b631600c4a3594
319 lines
8.4 KiB
C++
319 lines
8.4 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sw=4 et tw=78:
|
|
*
|
|
* 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/. */
|
|
|
|
#ifndef jsiter_h___
|
|
#define jsiter_h___
|
|
|
|
/*
|
|
* JavaScript iterators.
|
|
*/
|
|
#include "jscntxt.h"
|
|
#include "jsprvtd.h"
|
|
#include "jspubtd.h"
|
|
#include "jsversion.h"
|
|
|
|
#include "gc/Barrier.h"
|
|
#include "vm/Stack.h"
|
|
|
|
/*
|
|
* For cacheable native iterators, whether the iterator is currently active.
|
|
* Not serialized by XDR.
|
|
*/
|
|
#define JSITER_ACTIVE 0x1000
|
|
#define JSITER_UNREUSABLE 0x2000
|
|
|
|
namespace js {
|
|
|
|
struct NativeIterator
|
|
{
|
|
HeapPtrObject obj;
|
|
HeapPtr<JSFlatString> *props_array;
|
|
HeapPtr<JSFlatString> *props_cursor;
|
|
HeapPtr<JSFlatString> *props_end;
|
|
Shape **shapes_array;
|
|
uint32_t shapes_length;
|
|
uint32_t shapes_key;
|
|
uint32_t flags;
|
|
PropertyIteratorObject *next; /* Forms cx->enumerators list, garbage otherwise. */
|
|
|
|
bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; }
|
|
|
|
inline HeapPtr<JSFlatString> *begin() const {
|
|
return props_array;
|
|
}
|
|
|
|
inline HeapPtr<JSFlatString> *end() const {
|
|
return props_end;
|
|
}
|
|
|
|
size_t numKeys() const {
|
|
return end() - begin();
|
|
}
|
|
|
|
HeapPtr<JSFlatString> *current() const {
|
|
JS_ASSERT(props_cursor < props_end);
|
|
return props_cursor;
|
|
}
|
|
|
|
void incCursor() {
|
|
props_cursor = props_cursor + 1;
|
|
}
|
|
|
|
static NativeIterator *allocateIterator(JSContext *cx, uint32_t slength,
|
|
const js::AutoIdVector &props);
|
|
void init(RawObject obj, unsigned flags, uint32_t slength, uint32_t key);
|
|
|
|
void mark(JSTracer *trc);
|
|
};
|
|
|
|
class PropertyIteratorObject : public JSObject
|
|
{
|
|
public:
|
|
static Class class_;
|
|
|
|
inline NativeIterator *getNativeIterator() const;
|
|
inline void setNativeIterator(js::NativeIterator *ni);
|
|
|
|
private:
|
|
static void trace(JSTracer *trc, RawObject obj);
|
|
static void finalize(FreeOp *fop, RawObject obj);
|
|
};
|
|
|
|
/*
|
|
* Array iterators are roughly like this:
|
|
*
|
|
* Array.prototype.iterator = function iterator() {
|
|
* for (var i = 0; i < (this.length >>> 0); i++)
|
|
* yield this[i];
|
|
* }
|
|
*
|
|
* However they are not generators. They are a different class. The semantics
|
|
* of Array iterators will be given in the eventual ES6 spec in full detail.
|
|
*/
|
|
class ElementIteratorObject : public JSObject
|
|
{
|
|
public:
|
|
static JSObject *create(JSContext *cx, Handle<Value> target);
|
|
static JSFunctionSpec methods[];
|
|
|
|
enum {
|
|
TargetSlot,
|
|
IndexSlot,
|
|
NumSlots
|
|
};
|
|
|
|
static JSBool next(JSContext *cx, unsigned argc, Value *vp);
|
|
static bool next_impl(JSContext *cx, JS::CallArgs args);
|
|
};
|
|
|
|
bool
|
|
VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap);
|
|
|
|
bool
|
|
GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue vp);
|
|
|
|
JSObject *
|
|
GetIteratorObject(JSContext *cx, HandleObject obj, unsigned flags);
|
|
|
|
bool
|
|
VectorToKeyIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props,
|
|
MutableHandleValue vp);
|
|
|
|
bool
|
|
VectorToValueIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props,
|
|
MutableHandleValue vp);
|
|
|
|
/*
|
|
* Creates either a key or value iterator, depending on flags. For a value
|
|
* iterator, performs value-lookup to convert the given list of jsids.
|
|
*/
|
|
bool
|
|
EnumeratedIdVectorToIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props,
|
|
MutableHandleValue vp);
|
|
|
|
/*
|
|
* Convert the value stored in *vp to its iteration object. The flags should
|
|
* contain JSITER_ENUMERATE if js::ValueToIterator is called when enumerating
|
|
* for-in semantics are required, and when the caller can guarantee that the
|
|
* iterator will never be exposed to scripts.
|
|
*/
|
|
bool
|
|
ValueToIterator(JSContext *cx, unsigned flags, MutableHandleValue vp);
|
|
|
|
bool
|
|
CloseIterator(JSContext *cx, HandleObject iterObj);
|
|
|
|
bool
|
|
UnwindIteratorForException(JSContext *cx, js::HandleObject obj);
|
|
|
|
void
|
|
UnwindIteratorForUncatchableException(JSContext *cx, RawObject obj);
|
|
|
|
JSBool
|
|
IteratorConstructor(JSContext *cx, unsigned argc, Value *vp);
|
|
|
|
}
|
|
|
|
extern bool
|
|
js_SuppressDeletedProperty(JSContext *cx, js::HandleObject obj, jsid id);
|
|
|
|
extern bool
|
|
js_SuppressDeletedElement(JSContext *cx, js::HandleObject obj, uint32_t index);
|
|
|
|
extern bool
|
|
js_SuppressDeletedElements(JSContext *cx, js::HandleObject obj, uint32_t begin, uint32_t end);
|
|
|
|
/*
|
|
* IteratorMore() indicates whether another value is available. It might
|
|
* internally call iterobj.next() and then cache the value until its
|
|
* picked up by IteratorNext(). The value is cached in the current context.
|
|
*/
|
|
extern bool
|
|
js_IteratorMore(JSContext *cx, js::HandleObject iterobj, js::MutableHandleValue rval);
|
|
|
|
extern bool
|
|
js_IteratorNext(JSContext *cx, js::HandleObject iterobj, js::MutableHandleValue rval);
|
|
|
|
extern JSBool
|
|
js_ThrowStopIteration(JSContext *cx);
|
|
|
|
namespace js {
|
|
|
|
/*
|
|
* Get the next value from an iterator object.
|
|
*
|
|
* On success, store the next value in *vp and return true; if there are no
|
|
* more values, store the magic value JS_NO_ITER_VALUE in *vp and return true.
|
|
*/
|
|
inline bool
|
|
Next(JSContext *cx, HandleObject iter, MutableHandleValue vp)
|
|
{
|
|
if (!js_IteratorMore(cx, iter, vp))
|
|
return false;
|
|
if (vp.toBoolean())
|
|
return js_IteratorNext(cx, iter, vp);
|
|
vp.setMagic(JS_NO_ITER_VALUE);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Convenience class for imitating a JS level for-of loop. Typical usage:
|
|
*
|
|
* ForOfIterator it(cx, iterable);
|
|
* while (it.next()) {
|
|
* if (!DoStuff(cx, it.value()))
|
|
* return false;
|
|
* }
|
|
* if (!it.close())
|
|
* return false;
|
|
*
|
|
* The final it.close() check is needed in order to check for cases where
|
|
* any of the iterator operations fail.
|
|
*
|
|
* it.close() may be skipped only if something in the body of the loop fails
|
|
* and the failure is allowed to propagate on cx, as in this example if DoStuff
|
|
* fails. In that case, ForOfIterator's destructor does all necessary cleanup.
|
|
*/
|
|
class ForOfIterator
|
|
{
|
|
private:
|
|
JSContext *cx;
|
|
RootedObject iterator;
|
|
RootedValue currentValue;
|
|
bool ok;
|
|
bool closed;
|
|
|
|
ForOfIterator(const ForOfIterator &) MOZ_DELETE;
|
|
ForOfIterator &operator=(const ForOfIterator &) MOZ_DELETE;
|
|
|
|
public:
|
|
ForOfIterator(JSContext *cx, const Value &iterable)
|
|
: cx(cx), iterator(cx, NULL), currentValue(cx), closed(false)
|
|
{
|
|
RootedValue iterv(cx, iterable);
|
|
ok = ValueToIterator(cx, JSITER_FOR_OF, &iterv);
|
|
iterator = ok ? &iterv.get().toObject() : NULL;
|
|
}
|
|
|
|
~ForOfIterator() {
|
|
if (!closed)
|
|
close();
|
|
}
|
|
|
|
bool next() {
|
|
JS_ASSERT(!closed);
|
|
ok = ok && Next(cx, iterator, ¤tValue);
|
|
return ok && !currentValue.get().isMagic(JS_NO_ITER_VALUE);
|
|
}
|
|
|
|
Value &value() {
|
|
JS_ASSERT(ok);
|
|
JS_ASSERT(!closed);
|
|
return currentValue.get();
|
|
}
|
|
|
|
bool close() {
|
|
JS_ASSERT(!closed);
|
|
closed = true;
|
|
if (!iterator)
|
|
return false;
|
|
bool throwing = cx->isExceptionPending();
|
|
RootedValue exc(cx);
|
|
if (throwing) {
|
|
exc = cx->getPendingException();
|
|
cx->clearPendingException();
|
|
}
|
|
bool closedOK = CloseIterator(cx, iterator);
|
|
if (throwing && closedOK)
|
|
cx->setPendingException(exc);
|
|
return ok && !throwing && closedOK;
|
|
}
|
|
};
|
|
|
|
} /* namespace js */
|
|
|
|
#if JS_HAS_GENERATORS
|
|
|
|
/*
|
|
* Generator state codes.
|
|
*/
|
|
enum JSGeneratorState
|
|
{
|
|
JSGEN_NEWBORN, /* not yet started */
|
|
JSGEN_OPEN, /* started by a .next() or .send(undefined) call */
|
|
JSGEN_RUNNING, /* currently executing via .next(), etc., call */
|
|
JSGEN_CLOSING, /* close method is doing asynchronous return */
|
|
JSGEN_CLOSED /* closed, cannot be started or closed again */
|
|
};
|
|
|
|
struct JSGenerator
|
|
{
|
|
js::HeapPtrObject obj;
|
|
JSGeneratorState state;
|
|
js::FrameRegs regs;
|
|
js::PropertyIteratorObject *enumerators;
|
|
JSGenerator *prevGenerator;
|
|
js::StackFrame *fp;
|
|
js::HeapValue stackSnapshot[1];
|
|
};
|
|
|
|
extern JSObject *
|
|
js_NewGenerator(JSContext *cx);
|
|
|
|
namespace js {
|
|
|
|
bool
|
|
GeneratorHasMarkableFrame(JSGenerator *gen);
|
|
|
|
} /* namespace js */
|
|
#endif
|
|
|
|
extern JSObject *
|
|
js_InitIteratorClasses(JSContext *cx, js::HandleObject obj);
|
|
|
|
#endif /* jsiter_h___ */
|