1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qv4objectiterator_p.h"
4#include "qv4object_p.h"
5#include "qv4iterator_p.h"
6#include "qv4propertykey_p.h"
7#include <QtQml/private/qv4functionobject_p.h>
8
9using namespace QV4;
10
11void ForInIteratorPrototype::init(ExecutionEngine *)
12{
13 defineDefaultProperty(QStringLiteral("next"), code: method_next, argumentCount: 0);
14}
15
16PropertyKey ObjectIterator::next(Property *pd, PropertyAttributes *attrs)
17{
18 if (!object || !iterator)
19 return PropertyKey::invalid();
20
21 Scope scope(engine);
22 ScopedPropertyKey key(scope);
23
24 while (1) {
25 key = iterator->next(o: object, p: pd, attrs);
26 if (!key->isValid()) {
27 object = nullptr;
28 return key;
29 }
30 if ((!(flags & WithSymbols) && key->isSymbol()) ||
31 ((flags & EnumerableOnly) && !attrs->isEnumerable()))
32 continue;
33 return key;
34 }
35}
36
37ReturnedValue ObjectIterator::nextPropertyName(Value *value)
38{
39 if (!object)
40 return Encode::null();
41
42 PropertyAttributes attrs;
43 Scope scope(engine);
44 ScopedProperty p(scope);
45 ScopedPropertyKey key(scope, next(pd: p, attrs: &attrs));
46 if (!key->isValid())
47 return Encode::null();
48
49 *value = object->getValue(v: p->value, attrs);
50 if (key->isArrayIndex())
51 return Encode(key->asArrayIndex());
52 Q_ASSERT(key->isStringOrSymbol());
53 return key->asStringOrSymbol()->asReturnedValue();
54}
55
56ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value)
57{
58 if (!object)
59 return Encode::null();
60
61 PropertyAttributes attrs;
62 Scope scope(engine);
63 ScopedProperty p(scope);
64 ScopedPropertyKey key(scope, next(pd: p, attrs: &attrs));
65 if (!key->isValid())
66 return Encode::null();
67
68 *value = object->getValue(v: p->value, attrs);
69
70 return key->toStringOrSymbol(e: engine)->asReturnedValue();
71}
72
73ReturnedValue ObjectIterator::nextPropertyNameAsString()
74{
75 if (!object)
76 return Encode::null();
77
78 PropertyAttributes attrs;
79 Scope scope(engine);
80 ScopedPropertyKey key(scope, next(pd: nullptr, attrs: &attrs));
81 if (!key->isValid())
82 return Encode::null();
83
84 return key->toStringOrSymbol(e: engine)->asReturnedValue();
85}
86
87
88DEFINE_OBJECT_VTABLE(ForInIteratorObject);
89
90void Heap::ForInIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack)
91{
92 ForInIteratorObject *o = static_cast<ForInIteratorObject *>(that);
93 if (o->object)
94 o->object->mark(markStack);
95 if (o->current)
96 o->current->mark(markStack);
97 o->workArea[0].mark(markStack);
98 o->workArea[1].mark(markStack);
99 Object::markObjects(base: that, stack: markStack);
100}
101
102void Heap::ForInIteratorObject::destroy()
103{
104 delete iterator;
105}
106
107ReturnedValue ForInIteratorPrototype::method_next(const FunctionObject *b, const Value *thisObject, const Value *, int)
108{
109 const ForInIteratorObject *forIn = static_cast<const ForInIteratorObject *>(thisObject);
110 Q_ASSERT(forIn);
111 Scope scope(b);
112
113 ScopedPropertyKey key(scope, forIn->nextProperty());
114 bool done = false;
115 if (!key->isValid())
116 done = true;
117 ScopedStringOrSymbol s(scope, key->toStringOrSymbol(e: scope.engine));
118 return IteratorPrototype::createIterResultObject(engine: scope.engine, value: s, done);
119}
120
121
122PropertyKey ForInIteratorObject::nextProperty() const
123{
124 if (!d()->current)
125 return PropertyKey::invalid();
126
127 Scope scope(this);
128 ScopedObject c(scope, d()->current);
129 ScopedObject t(scope, d()->target);
130 ScopedObject o(scope);
131 ScopedProperty p(scope);
132 ScopedPropertyKey key(scope);
133 PropertyAttributes attrs;
134
135 while (1) {
136 while (1) {
137 key = d()->iterator->next(o: t, p, attrs: &attrs);
138 if (!key->isValid())
139 break;
140 if (!attrs.isEnumerable() || key->isSymbol())
141 continue;
142 // check the property is not already defined earlier in the proto chain
143 if (d()->current != d()->object) {
144 o = d()->object;
145 bool shadowed = false;
146 while (o && o->d() != c->heapObject()) {
147 if (o->getOwnProperty(id: key) != Attr_Invalid) {
148 shadowed = true;
149 break;
150 }
151 o = o->getPrototypeOf();
152 }
153 if (shadowed)
154 continue;
155 }
156 return key;
157 }
158
159 c = c->getPrototypeOf();
160 d()->current.set(e: scope.engine, newVal: c->d());
161 if (!c)
162 break;
163 delete d()->iterator;
164 d()->iterator = c->ownPropertyKeys(target: t.getRef());
165 d()->target.set(e: scope.engine, newVal: t->d());
166 if (!d()->iterator) {
167 scope.engine->throwTypeError();
168 return PropertyKey::invalid();
169 }
170 }
171 return PropertyKey::invalid();
172}
173

source code of qtdeclarative/src/qml/jsruntime/qv4objectiterator.cpp