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 | |
9 | using namespace QV4; |
10 | |
11 | void ForInIteratorPrototype::init(ExecutionEngine *) |
12 | { |
13 | defineDefaultProperty(QStringLiteral("next" ), code: method_next, argumentCount: 0); |
14 | } |
15 | |
16 | PropertyKey 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 | |
37 | ReturnedValue 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 | |
56 | ReturnedValue 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 | |
73 | ReturnedValue 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 | |
88 | DEFINE_OBJECT_VTABLE(ForInIteratorObject); |
89 | |
90 | void 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 | |
102 | void Heap::ForInIteratorObject::destroy() |
103 | { |
104 | delete iterator; |
105 | } |
106 | |
107 | ReturnedValue 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 | |
122 | PropertyKey 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 | |