Rename ForeachIterator to ForInIterator

As it's being used for for(... in ...) loops. Also add a ES6
compatible iterator interface to it, so that we can unify
the handling of for-in and for-of.

Change-Id: I264f88ed049484945f5ea7e8bdf0227187456ba2
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Lars Knoll 2018-05-03 21:50:18 +02:00
parent cff55a7a0d
commit 4f086e3aac
6 changed files with 53 additions and 20 deletions

View File

@ -57,7 +57,7 @@ QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v)
QV4::Scope scope(e);
QV4::ScopedObject o(scope, QJSValuePrivate::getValue(&v));
iterator.set(e, e->newForEachIteratorObject(o));
iterator.set(e, e->newForInIteratorObject(o));
}
@ -102,7 +102,7 @@ QJSValueIterator::QJSValueIterator(const QJSValue& object)
if (!v4)
return;
QV4::Scope scope(v4);
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
QV4::Scoped<QV4::ForInIteratorObject> it(scope, d_ptr->iterator.value());
it->d()->it().flags = QV4::ObjectIterator::NoFlags;
QV4::ScopedString nm(scope);
QV4::Property nextProperty;
@ -153,7 +153,7 @@ bool QJSValueIterator::next()
if (!v4)
return false;
QV4::Scope scope(v4);
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
QV4::Scoped<QV4::ForInIteratorObject> it(scope, d_ptr->iterator.value());
QV4::ScopedString nm(scope);
QV4::Property nextProperty;
QV4::PropertyAttributes nextAttributes;
@ -229,8 +229,8 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object)
QV4::Scope scope(v4);
QV4::ScopedObject o(scope, QJSValuePrivate::getValue(&object));
d_ptr->iterator.set(v4, v4->newForEachIteratorObject(o));
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
d_ptr->iterator.set(v4, v4->newForInIteratorObject(o));
QV4::Scoped<QV4::ForInIteratorObject> it(scope, d_ptr->iterator.value());
it->d()->it().flags = QV4::ObjectIterator::NoFlags;
QV4::ScopedString nm(scope);
QV4::Property nextProperty;

View File

@ -415,6 +415,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(global);
jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(global);
jsObjects[IteratorProto] = memoryManager->allocate<IteratorPrototype>();
jsObjects[ForInIteratorProto] = memoryManager->allocObject<ForInIteratorPrototype>(newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype()));
jsObjects[ArrayIteratorProto] = memoryManager->allocObject<ArrayIteratorPrototype>(newInternalClass(ArrayIteratorPrototype::staticVTable(), iteratorPrototype()));
jsObjects[StringIteratorProto] = memoryManager->allocObject<StringIteratorPrototype>(newInternalClass(StringIteratorPrototype::staticVTable(), iteratorPrototype()));
@ -438,6 +439,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor());
static_cast<IteratorPrototype *>(iteratorPrototype())->init(this);
static_cast<ForInIteratorPrototype *>(forInIteratorPrototype())->init(this);
static_cast<ArrayIteratorPrototype *>(arrayIteratorPrototype())->init(this);
static_cast<StringIteratorPrototype *>(stringIteratorPrototype())->init(this);
@ -790,10 +792,10 @@ Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v)
return memoryManager->allocate<VariantObject>(v);
}
Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o)
Heap::Object *ExecutionEngine::newForInIteratorObject(Object *o)
{
Scope scope(this);
ScopedObject obj(scope, memoryManager->allocate<ForEachIteratorObject>(o));
ScopedObject obj(scope, memoryManager->allocate<ForInIteratorObject>(o));
return obj->d();
}

View File

@ -190,6 +190,7 @@ public:
ValueTypeProto,
SignalHandlerProto,
IteratorProto,
ForInIteratorProto,
ArrayIteratorProto,
StringIteratorProto,
@ -274,6 +275,7 @@ public:
Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); }
Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); }
Object *iteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + IteratorProto); }
Object *forInIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ForInIteratorProto); }
Object *arrayIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayIteratorProto); }
Object *stringIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringIteratorProto); }
@ -489,7 +491,7 @@ public:
Heap::Object *newVariantObject(const QVariant &v);
Heap::Object *newForEachIteratorObject(Object *o);
Heap::Object *newForInIteratorObject(Object *o);
Heap::Object *newArrayIteratorObject(Object *o);
Heap::QmlContext *qmlContext() const;

View File

@ -42,9 +42,29 @@
#include "qv4identifier_p.h"
#include "qv4argumentsobject_p.h"
#include "qv4string_p.h"
#include "qv4iterator_p.h"
using namespace QV4;
void ForInIteratorPrototype::init(ExecutionEngine *)
{
defineDefaultProperty(QStringLiteral("next"), method_next, 0);
}
ReturnedValue ForInIteratorPrototype::method_next(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
const ForInIteratorObject *forIn = thisObject->as<ForInIteratorObject>();
Q_ASSERT(forIn);
Scope scope(b->engine());
ScopedValue n(scope, forIn->nextPropertyName());
bool done = false;
if (n->asReturnedValue() == Encode::null()) {
done = true;
n = Primitive::undefinedValue();
}
return IteratorPrototype::createIterResultObject(scope.engine, n, done);
}
void ObjectIterator::init(const Object *o)
{
object->setM(o ? o->m() : nullptr);
@ -175,11 +195,11 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString()
}
DEFINE_OBJECT_VTABLE(ForEachIteratorObject);
DEFINE_OBJECT_VTABLE(ForInIteratorObject);
void Heap::ForEachIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack)
void Heap::ForInIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack)
{
ForEachIteratorObject *o = static_cast<ForEachIteratorObject *>(that);
ForInIteratorObject *o = static_cast<ForInIteratorObject *>(that);
o->workArea[0].mark(markStack);
o->workArea[1].mark(markStack);
Object::markObjects(that, markStack);

View File

@ -111,7 +111,7 @@ private:
};
namespace Heap {
struct ForEachIteratorObject : Object {
struct ForInIteratorObject : Object {
void init(QV4::Object *o);
ObjectIterator &it() { return *reinterpret_cast<ObjectIterator*>(&itData); }
Value workArea[2];
@ -123,15 +123,24 @@ private:
}
struct ForEachIteratorObject: Object {
V4_OBJECT2(ForEachIteratorObject, Object)
Q_MANAGED_TYPE(ForeachIteratorObject)
struct ForInIteratorPrototype : Object
{
V4_PROTOTYPE(iteratorPrototype)
void init(ExecutionEngine *engine);
ReturnedValue nextPropertyName() { return d()->it().nextPropertyNameAsString(); }
static ReturnedValue method_next(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
};
struct ForInIteratorObject: Object {
V4_OBJECT2(ForInIteratorObject, Object)
Q_MANAGED_TYPE(ForeachIteratorObject)
V4_PROTOTYPE(forInIteratorPrototype)
ReturnedValue nextPropertyName() const { return d()->it().nextPropertyNameAsString(); }
};
inline
void Heap::ForEachIteratorObject::init(QV4::Object *o)
void Heap::ForInIteratorObject::init(QV4::Object *o)
{
Object::init();
it() = ObjectIterator(internalClass->engine, workArea, workArea + 1, o,

View File

@ -701,15 +701,15 @@ ReturnedValue Runtime::method_foreachIterator(ExecutionEngine *engine, const Val
ScopedObject o(scope, (Object *)nullptr);
if (!in.isNullOrUndefined())
o = in.toObject(engine);
return engine->newForEachIteratorObject(o)->asReturnedValue();
return engine->newForInIteratorObject(o)->asReturnedValue();
}
ReturnedValue Runtime::method_foreachNextPropertyName(const Value &foreach_iterator)
{
Q_ASSERT(foreach_iterator.isObject());
ForEachIteratorObject *it = static_cast<ForEachIteratorObject *>(foreach_iterator.objectValue());
Q_ASSERT(it->as<ForEachIteratorObject>());
ForInIteratorObject *it = static_cast<ForInIteratorObject *>(foreach_iterator.objectValue());
Q_ASSERT(it->as<ForInIteratorObject>());
return it->nextPropertyName();
}