1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qv4reflect_p.h"
41#include "qv4symbol_p.h"
42#include "qv4runtimeapi_p.h"
43#include "qv4objectproto_p.h"
44#include "qv4propertykey_p.h"
45#include "qv4objectiterator_p.h"
46
47using namespace QV4;
48
49DEFINE_OBJECT_VTABLE(Reflect);
50
51void Heap::Reflect::init()
52{
53 Object::init();
54 Scope scope(internalClass->engine);
55 ScopedObject r(scope, this);
56
57 r->defineDefaultProperty(QStringLiteral("apply"), code: QV4::Reflect::method_apply, argumentCount: 3);
58 r->defineDefaultProperty(QStringLiteral("construct"), code: QV4::Reflect::method_construct, argumentCount: 2);
59 r->defineDefaultProperty(QStringLiteral("defineProperty"), code: QV4::Reflect::method_defineProperty, argumentCount: 3);
60 r->defineDefaultProperty(QStringLiteral("deleteProperty"), code: QV4::Reflect::method_deleteProperty, argumentCount: 2);
61 r->defineDefaultProperty(QStringLiteral("get"), code: QV4::Reflect::method_get, argumentCount: 2);
62 r->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), code: QV4::Reflect::method_getOwnPropertyDescriptor, argumentCount: 2);
63 r->defineDefaultProperty(QStringLiteral("getPrototypeOf"), code: QV4::Reflect::method_getPrototypeOf, argumentCount: 1);
64 r->defineDefaultProperty(QStringLiteral("has"), code: QV4::Reflect::method_has, argumentCount: 2);
65 r->defineDefaultProperty(QStringLiteral("isExtensible"), code: QV4::Reflect::method_isExtensible, argumentCount: 1);
66 r->defineDefaultProperty(QStringLiteral("ownKeys"), code: QV4::Reflect::method_ownKeys, argumentCount: 1);
67 r->defineDefaultProperty(QStringLiteral("preventExtensions"), code: QV4::Reflect::method_preventExtensions, argumentCount: 1);
68 r->defineDefaultProperty(QStringLiteral("set"), code: QV4::Reflect::method_set, argumentCount: 3);
69 r->defineDefaultProperty(QStringLiteral("setPrototypeOf"), code: QV4::Reflect::method_setPrototypeOf, argumentCount: 2);
70}
71
72struct CallArgs {
73 Value *argv;
74 int argc;
75};
76
77static CallArgs createListFromArrayLike(Scope &scope, const Object *o)
78{
79 int len = o->getLength();
80 Value *arguments = scope.alloc(nValues: len);
81
82 for (int i = 0; i < len; ++i) {
83 arguments[i] = o->get(idx: i);
84 if (scope.hasException())
85 return { .argv: nullptr, .argc: 0 };
86 }
87 return { .argv: arguments, .argc: len };
88}
89
90ReturnedValue Reflect::method_apply(const FunctionObject *f, const Value *, const Value *argv, int argc)
91{
92 Scope scope(f);
93 if (argc < 3 || !argv[0].isFunctionObject() || !argv[2].isObject())
94 return scope.engine->throwTypeError();
95
96 const Object *o = static_cast<const Object *>(argv + 2);
97 CallArgs arguments = createListFromArrayLike(scope, o);
98 if (scope.hasException())
99 return Encode::undefined();
100
101 return checkedResult(v4: scope.engine, result: static_cast<const FunctionObject &>(argv[0]).call(
102 thisObject: &argv[1], argv: arguments.argv, argc: arguments.argc));
103}
104
105ReturnedValue Reflect::method_construct(const FunctionObject *f, const Value *, const Value *argv, int argc)
106{
107 Scope scope(f);
108 if (argc < 2 || !argv[1].isObject())
109 return scope.engine->throwTypeError();
110 const FunctionObject *target = argv[0].as<FunctionObject>();
111 const FunctionObject *newTarget = argc == 3 ? argv[2].as<FunctionObject>() : target;
112 if (!target || !target->isConstructor() || !newTarget || !newTarget->isConstructor())
113 return scope.engine->throwTypeError();
114
115 const Object *o = static_cast<const Object *>(argv + 1);
116 CallArgs arguments = createListFromArrayLike(scope, o);
117 if (scope.hasException())
118 return Encode::undefined();
119
120 return target->callAsConstructor(argv: arguments.argv, argc: arguments.argc, newTarget);
121}
122
123ReturnedValue Reflect::method_defineProperty(const FunctionObject *f, const Value *, const Value *argv, int argc)
124{
125 Scope scope(f);
126 if (!argc || !argv[0].isObject())
127 return scope.engine->throwTypeError();
128
129 ScopedObject O(scope, argv[0]);
130 ScopedPropertyKey name(scope, (argc > 1 ? argv[1] : Value::undefinedValue()).toPropertyKey(e: scope.engine));
131 if (scope.engine->hasException)
132 return QV4::Encode::undefined();
133
134 ScopedValue attributes(scope, argc > 2 ? argv[2] : Value::undefinedValue());
135 ScopedProperty pd(scope);
136 PropertyAttributes attrs;
137 ObjectPrototype::toPropertyDescriptor(engine: scope.engine, v: attributes, desc: pd, attrs: &attrs);
138 if (scope.engine->hasException)
139 return QV4::Encode::undefined();
140
141 bool result = O->defineOwnProperty(id: name, p: pd, attrs);
142
143 return Encode(result);
144}
145
146ReturnedValue Reflect::method_deleteProperty(const FunctionObject *f, const Value *, const Value *argv, int argc)
147{
148 ExecutionEngine *e = f->engine();
149 if (!argc || !argv[0].isObject())
150 return e->throwTypeError();
151
152 bool result = Runtime::DeleteProperty_NoThrow::call(e, argv[0], argc > 1 ? argv[1] : Value::undefinedValue());
153 return Encode(result);
154}
155
156ReturnedValue Reflect::method_get(const FunctionObject *f, const Value *, const Value *argv, int argc)
157{
158 Scope scope(f);
159 if (!argc || !argv[0].isObject())
160 return scope.engine->throwTypeError();
161
162 ScopedObject o(scope, static_cast<const Object *>(argv));
163 Value undef = Value::undefinedValue();
164 const Value *index = argc > 1 ? &argv[1] : &undef;
165 ScopedPropertyKey name(scope, index->toPropertyKey(e: scope.engine));
166 if (scope.hasException())
167 return Encode::undefined();
168 ScopedValue receiver(scope, argc > 2 ? argv[2] : *o);
169
170 return Encode(o->get(id: name, receiver));
171}
172
173ReturnedValue Reflect::method_getOwnPropertyDescriptor(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
174{
175 if (!argc || !argv[0].isObject())
176 return f->engine()->throwTypeError();
177
178 return ObjectPrototype::method_getOwnPropertyDescriptor(f, thisObject, argv, argc);
179}
180
181ReturnedValue Reflect::method_getPrototypeOf(const FunctionObject *f, const Value *, const Value *argv, int argc)
182{
183 if (!argc || !argv[0].isObject())
184 return f->engine()->throwTypeError();
185
186 const Object *o = static_cast<const Object *>(argv);
187 Heap::Object *p = o->getPrototypeOf();
188 return (p ? p->asReturnedValue() : Encode::null());
189}
190
191ReturnedValue Reflect::method_has(const FunctionObject *f, const Value *, const Value *argv, int argc)
192{
193 Scope scope(f);
194 if (!argc || !argv[0].isObject())
195 return scope.engine->throwTypeError();
196
197 ScopedObject o(scope, static_cast<const Object *>(argv));
198 Value undef = Value::undefinedValue();
199 const Value *index = argc > 1 ? &argv[1] : &undef;
200
201 ScopedPropertyKey name(scope, index->toPropertyKey(e: scope.engine));
202 if (scope.engine->hasException)
203 return false;
204
205 return Encode(o->hasProperty(id: name));
206}
207
208ReturnedValue Reflect::method_isExtensible(const FunctionObject *f, const Value *, const Value *argv, int argc)
209{
210 if (!argc || !argv[0].isObject())
211 return f->engine()->throwTypeError();
212
213 const Object *o = static_cast<const Object *>(argv);
214 return Encode(o->isExtensible());
215}
216
217
218ReturnedValue Reflect::method_ownKeys(const FunctionObject *f, const Value *, const Value *argv, int argc)
219{
220 if (!argc || !argv[0].isObject())
221 return f->engine()->throwTypeError();
222
223 Scope scope(f);
224 if (!argc)
225 return scope.engine->throwTypeError();
226
227 ScopedObject O(scope, argv[0].toObject(e: scope.engine));
228 if (!O)
229 return Encode::undefined();
230
231 ScopedArrayObject keys(scope, scope.engine->newArrayObject());
232
233 ObjectIterator it(scope, O, ObjectIterator::WithSymbols);
234 ScopedPropertyKey key(scope);
235 ScopedValue v(scope);
236 while (1) {
237 key = it.next();
238 if (!key->isValid())
239 break;
240 v = key->toStringOrSymbol(e: scope.engine);
241 keys->push_back(v);
242 }
243
244 return keys->asReturnedValue();
245
246}
247
248ReturnedValue Reflect::method_preventExtensions(const FunctionObject *f, const Value *, const Value *argv, int argc)
249{
250 Scope scope(f);
251 if (!argc || !argv[0].isObject())
252 return scope.engine->throwTypeError();
253
254 ScopedObject o(scope, static_cast<const Object *>(argv));
255 return Encode(o->preventExtensions());
256}
257
258ReturnedValue Reflect::method_set(const FunctionObject *f, const Value *, const Value *argv, int argc)
259{
260 Scope scope(f);
261 if (!argc || !argv[0].isObject())
262 return scope.engine->throwTypeError();
263
264 ScopedObject o(scope, static_cast<const Object *>(argv));
265 Value undef = Value::undefinedValue();
266 const Value *index = argc > 1 ? &argv[1] : &undef;
267 const Value &val = argc > 2 ? argv[2] : undef;
268 ScopedValue receiver(scope, argc >3 ? argv[3] : argv[0]);
269
270 ScopedPropertyKey propertyKey(scope, index->toPropertyKey(e: scope.engine));
271 if (scope.engine->hasException)
272 return false;
273 bool result = o->put(id: propertyKey, v: val, receiver);
274 return Encode(result);
275}
276
277ReturnedValue Reflect::method_setPrototypeOf(const FunctionObject *f, const Value *, const Value *argv, int argc)
278{
279 if (argc < 2 || !argv[0].isObject() || (!argv[1].isNull() && !argv[1].isObject()))
280 return f->engine()->throwTypeError();
281
282 Scope scope(f);
283 ScopedObject o(scope, static_cast<const Object *>(argv));
284 const Object *proto = argv[1].isNull() ? nullptr : static_cast<const Object *>(argv + 1);
285 return Encode(o->setPrototypeOf(proto));
286}
287

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