1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtScript 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 "qscriptdeclarativeclass_p.h"
41#include "qscriptdeclarativeobject_p.h"
42#include "qscriptobject_p.h"
43#include "qscriptstaticscopeobject_p.h"
44#include <QtScript/qscriptstring.h>
45#include <QtScript/qscriptengine.h>
46#include <QtScript/qscriptengineagent.h>
47#include <private/qscriptengine_p.h>
48#include <private/qscriptvalue_p.h>
49#include <private/qscriptqobject_p.h>
50#include <private/qscriptactivationobject_p.h>
51#include <QtCore/qstringlist.h>
52
53QT_BEGIN_NAMESPACE
54
55/*!
56\class QScriptDeclarativeClass::Value
57\internal
58\brief The QScriptDeclarativeClass::Value class acts as a container for JavaScript data types.
59
60QScriptDeclarativeClass::Value class is similar to QScriptValue, but it is slightly faster.
61Unlike QScriptValue, however, Value instances cannot be stored as they may not survive garbage
62collection. If you need to store a Value, convert it to a QScriptValue and store that.
63*/
64
65QScriptDeclarativeClass::Value::Value()
66{
67 new (this) JSC::JSValue(JSC::jsUndefined());
68}
69
70QScriptDeclarativeClass::Value::Value(const Value &other)
71{
72 new (this) JSC::JSValue((JSC::JSValue &)other);
73}
74
75static QScriptDeclarativeClass::Value jscToValue(const JSC::JSValue &val)
76{
77 return QScriptDeclarativeClass::Value((QScriptDeclarativeClass::Value &)val);
78}
79
80QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, int value)
81{
82 new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(context: ctxt), value);
83}
84
85QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, uint value)
86{
87 new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(context: ctxt), value);
88}
89
90QScriptDeclarativeClass::Value::Value(QScriptContext *, bool value)
91{
92 if (value)
93 new (this) JSC::JSValue(JSC::JSValue::JSTrue);
94 else
95 new (this) JSC::JSValue(JSC::JSValue::JSFalse);
96}
97
98QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, double value)
99{
100 new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(context: ctxt), value);
101}
102
103QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, float value)
104{
105 new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(context: ctxt), value);
106}
107
108QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, const QString &value)
109{
110 new (this) JSC::JSValue(JSC::jsString(exec: QScriptEnginePrivate::frameForContext(context: ctxt), s: value));
111}
112
113QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, const QScriptValue &value)
114{
115 new (this) JSC::JSValue(QScriptEnginePrivate::get(q: ctxt->engine())->scriptValueToJSCValue(value));
116}
117
118QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, int value)
119{
120 new (this) JSC::JSValue(QScriptEnginePrivate::get(q: eng)->currentFrame, value);
121}
122
123QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, uint value)
124{
125 new (this) JSC::JSValue(QScriptEnginePrivate::get(q: eng)->currentFrame, value);
126}
127
128QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, bool value)
129{
130 if (value)
131 new (this) JSC::JSValue(JSC::JSValue::JSTrue);
132 else
133 new (this) JSC::JSValue(JSC::JSValue::JSFalse);
134}
135
136QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, double value)
137{
138 new (this) JSC::JSValue(QScriptEnginePrivate::get(q: eng)->currentFrame, value);
139}
140
141QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, float value)
142{
143 new (this) JSC::JSValue(QScriptEnginePrivate::get(q: eng)->currentFrame, value);
144}
145
146QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, const QString &value)
147{
148 new (this) JSC::JSValue(JSC::jsString(exec: QScriptEnginePrivate::get(q: eng)->currentFrame, s: value));
149}
150
151QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, const QScriptValue &value)
152{
153 new (this) JSC::JSValue(QScriptEnginePrivate::get(q: eng)->scriptValueToJSCValue(value));
154}
155
156QScriptDeclarativeClass::Value::~Value()
157{
158 ((JSC::JSValue *)(this))->~JSValue();
159}
160
161QScriptValue QScriptDeclarativeClass::Value::toScriptValue(QScriptEngine *engine) const
162{
163 return QScriptEnginePrivate::get(q: engine)->scriptValueFromJSCValue(value: (JSC::JSValue &)*this);
164}
165
166QScriptDeclarativeClass::PersistentIdentifier::PersistentIdentifier()
167 : identifier(0), engine(0)
168{
169 new (&d) JSC::Identifier();
170}
171
172QScriptDeclarativeClass::PersistentIdentifier::~PersistentIdentifier()
173{
174 if (engine) {
175 QScript::APIShim shim(engine);
176 ((JSC::Identifier &)d).JSC::Identifier::~Identifier();
177 } else {
178 ((JSC::Identifier &)d).JSC::Identifier::~Identifier();
179 }
180}
181
182QScriptDeclarativeClass::PersistentIdentifier::PersistentIdentifier(const PersistentIdentifier &other)
183{
184 identifier = other.identifier;
185 engine = other.engine;
186 new (&d) JSC::Identifier((JSC::Identifier &)(other.d));
187}
188
189QScriptDeclarativeClass::PersistentIdentifier &
190QScriptDeclarativeClass::PersistentIdentifier::operator=(const PersistentIdentifier &other)
191{
192 identifier = other.identifier;
193 engine = other.engine;
194 ((JSC::Identifier &)d) = (JSC::Identifier &)(other.d);
195 return *this;
196}
197
198QString QScriptDeclarativeClass::PersistentIdentifier::toString() const
199{
200 return ((JSC::Identifier &)d).ustring();
201}
202
203QScriptDeclarativeClass::QScriptDeclarativeClass(QScriptEngine *engine)
204: d_ptr(new QScriptDeclarativeClassPrivate)
205{
206 Q_ASSERT(sizeof(void*) == sizeof(JSC::Identifier));
207 d_ptr->q_ptr = this;
208 d_ptr->engine = engine;
209}
210
211QScriptValue QScriptDeclarativeClass::newObject(QScriptEngine *engine,
212 QScriptDeclarativeClass *scriptClass,
213 Object *object)
214{
215 Q_ASSERT(engine);
216 Q_ASSERT(scriptClass);
217
218 QScriptEnginePrivate *p = static_cast<QScriptEnginePrivate *>(QObjectPrivate::get(o: engine));
219 QScript::APIShim shim(p);
220
221 JSC::ExecState* exec = p->currentFrame;
222 QScriptObject *result = new (exec) QScriptObject(p->scriptObjectStructure);
223 result->setDelegate(new QScript::DeclarativeObjectDelegate(scriptClass, object));
224 return p->scriptValueFromJSCValue(value: result);
225}
226
227QScriptDeclarativeClass::Value
228QScriptDeclarativeClass::newObjectValue(QScriptEngine *engine,
229 QScriptDeclarativeClass *scriptClass,
230 Object *object)
231{
232 Q_ASSERT(engine);
233 Q_ASSERT(scriptClass);
234
235 QScriptEnginePrivate *p = static_cast<QScriptEnginePrivate *>(QObjectPrivate::get(o: engine));
236 QScript::APIShim shim(p);
237
238 JSC::ExecState* exec = p->currentFrame;
239 QScriptObject *result = new (exec) QScriptObject(p->scriptObjectStructure);
240 result->setDelegate(new QScript::DeclarativeObjectDelegate(scriptClass, object));
241 return jscToValue(JSC::JSValue(result));
242}
243
244QScriptDeclarativeClass *QScriptDeclarativeClass::scriptClass(const QScriptValue &v)
245{
246 QScriptValuePrivate *d = QScriptValuePrivate::get(q: v);
247 if (!d || !d->isJSC())
248 return 0;
249 return QScriptEnginePrivate::declarativeClass(v: d->jscValue);
250}
251
252QScriptDeclarativeClass::Object *QScriptDeclarativeClass::object(const QScriptValue &v)
253{
254 QScriptValuePrivate *d = QScriptValuePrivate::get(q: v);
255 if (!d || !d->isJSC())
256 return 0;
257 return QScriptEnginePrivate::declarativeObject(v: d->jscValue);
258}
259
260QScriptValue QScriptDeclarativeClass::function(const QScriptValue &v, const Identifier &name)
261{
262 QScriptValuePrivate *d = QScriptValuePrivate::get(q: v);
263
264 if (!d->isObject())
265 return QScriptValue();
266
267 QScript::APIShim shim(d->engine);
268 JSC::ExecState *exec = d->engine->currentFrame;
269 JSC::JSObject *object = d->jscValue.getObject();
270 JSC::PropertySlot slot(const_cast<JSC::JSObject*>(object));
271 JSC::JSValue result;
272
273 JSC::Identifier id(exec, (JSC::UString::Rep *)name);
274
275 if (const_cast<JSC::JSObject*>(object)->getOwnPropertySlot(exec, propertyName: id, slot)) {
276 result = slot.getValue(exec, propertyName: id);
277 if (QScript::isFunction(value: result))
278 return d->engine->scriptValueFromJSCValue(value: result);
279 }
280
281 return QScriptValue();
282}
283
284QScriptValue QScriptDeclarativeClass::property(const QScriptValue &v, const Identifier &name)
285{
286 QScriptValuePrivate *d = QScriptValuePrivate::get(q: v);
287
288 if (!d->isObject())
289 return QScriptValue();
290
291 QScript::APIShim shim(d->engine);
292 JSC::ExecState *exec = d->engine->currentFrame;
293 JSC::JSObject *object = d->jscValue.getObject();
294 JSC::PropertySlot slot(const_cast<JSC::JSObject*>(object));
295 JSC::JSValue result;
296
297 JSC::Identifier id(exec, (JSC::UString::Rep *)name);
298
299 if (const_cast<JSC::JSObject*>(object)->getOwnPropertySlot(exec, propertyName: id, slot)) {
300 result = slot.getValue(exec, propertyName: id);
301 return d->engine->scriptValueFromJSCValue(value: result);
302 }
303
304 return QScriptValue();
305}
306
307QScriptDeclarativeClass::Value
308QScriptDeclarativeClass::functionValue(const QScriptValue &v, const Identifier &name)
309{
310 QScriptValuePrivate *d = QScriptValuePrivate::get(q: v);
311
312 if (!d->isObject())
313 return Value();
314
315 QScript::APIShim shim(d->engine);
316 JSC::ExecState *exec = d->engine->currentFrame;
317 JSC::JSObject *object = d->jscValue.getObject();
318 JSC::PropertySlot slot(const_cast<JSC::JSObject*>(object));
319 JSC::JSValue result;
320
321 JSC::Identifier id(exec, (JSC::UString::Rep *)name);
322
323 if (const_cast<JSC::JSObject*>(object)->getOwnPropertySlot(exec, propertyName: id, slot)) {
324 result = slot.getValue(exec, propertyName: id);
325 if (QScript::isFunction(value: result))
326 return jscToValue(val: result);
327 }
328
329 return Value();
330}
331
332QScriptDeclarativeClass::Value
333QScriptDeclarativeClass::propertyValue(const QScriptValue &v, const Identifier &name)
334{
335 QScriptValuePrivate *d = QScriptValuePrivate::get(q: v);
336
337 if (!d->isObject())
338 return Value();
339
340 QScript::APIShim shim(d->engine);
341 JSC::ExecState *exec = d->engine->currentFrame;
342 JSC::JSObject *object = d->jscValue.getObject();
343 JSC::PropertySlot slot(const_cast<JSC::JSObject*>(object));
344 JSC::JSValue result;
345
346 JSC::Identifier id(exec, (JSC::UString::Rep *)name);
347
348 if (const_cast<JSC::JSObject*>(object)->getOwnPropertySlot(exec, propertyName: id, slot)) {
349 result = slot.getValue(exec, propertyName: id);
350 return jscToValue(val: result);
351 }
352
353 return Value();
354}
355
356/*
357Returns the scope chain entry at \a index. If index is less than 0, returns
358entries starting at the end. For example, scopeChainValue(context, -1) will return
359the value last in the scope chain.
360*/
361QScriptValue QScriptDeclarativeClass::scopeChainValue(QScriptContext *context, int index)
362{
363 context->activationObject(); //ensure the creation of the normal scope for native context
364 const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(context);
365 QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(exec: frame);
366 QScript::APIShim shim(engine);
367
368 JSC::ScopeChainNode *node = frame->scopeChain();
369 JSC::ScopeChainIterator it(node);
370
371 if (index < 0) {
372 int count = 0;
373 for (it = node->begin(); it != node->end(); ++it)
374 ++count;
375
376 index = qAbs(t: index);
377 if (index > count)
378 return QScriptValue();
379 else
380 index = count - index;
381 }
382
383 for (it = node->begin(); it != node->end(); ++it) {
384
385 if (index == 0) {
386
387 JSC::JSObject *object = *it;
388 if (!object) return QScriptValue();
389
390 if (object->inherits(info: &QScript::QScriptActivationObject::info)
391 && (static_cast<QScript::QScriptActivationObject*>(object)->delegate() != 0)) {
392 // Return the object that property access is being delegated to
393 object = static_cast<QScript::QScriptActivationObject*>(object)->delegate();
394 }
395 return engine->scriptValueFromJSCValue(value: object);
396
397 } else {
398 --index;
399 }
400
401 }
402
403 return QScriptValue();
404}
405
406/*!
407 Enters a new execution context and returns the associated
408 QScriptContext object.
409
410 Once you are done with the context, you should call popContext() to
411 restore the old context.
412
413 By default, the `this' object of the new context is the Global Object.
414 The context's \l{QScriptContext::callee()}{callee}() will be invalid.
415
416 The context's scope chain initially contains only the Global Object
417 and the QScriptContext's activation object.
418
419 This function behaves exactly like QScriptEngine::popContext();
420 it exists because QScriptEngine::popContext() used to have a bug
421 that caused the scope chain of the new context to be incorrect.
422*/
423QScriptContext * QScriptDeclarativeClass::pushCleanContext(QScriptEngine *engine)
424{
425 if (!engine)
426 return 0;
427
428 return engine->pushContext();
429}
430
431QScriptDeclarativeClass::~QScriptDeclarativeClass()
432{
433}
434
435QScriptEngine *QScriptDeclarativeClass::engine() const
436{
437 return d_ptr->engine;
438}
439
440bool QScriptDeclarativeClass::supportsCall() const
441{
442 return d_ptr->supportsCall;
443}
444
445void QScriptDeclarativeClass::setSupportsCall(bool c)
446{
447 d_ptr->supportsCall = c;
448}
449
450QScriptDeclarativeClass::PersistentIdentifier
451QScriptDeclarativeClass::createPersistentIdentifier(const QString &str)
452{
453 QScriptEnginePrivate *p =
454 static_cast<QScriptEnginePrivate *>(QObjectPrivate::get(o: d_ptr->engine));
455 QScript::APIShim shim(p);
456 JSC::ExecState* exec = p->currentFrame;
457
458 PersistentIdentifier rv(p);
459 new (&rv.d) JSC::Identifier(exec, (UChar *)str.constData(), str.size());
460 rv.identifier = (void *)((JSC::Identifier &)rv.d).ustring().rep();
461 return rv;
462}
463
464QScriptDeclarativeClass::PersistentIdentifier
465QScriptDeclarativeClass::createPersistentIdentifier(const Identifier &id)
466{
467 QScriptEnginePrivate *p =
468 static_cast<QScriptEnginePrivate *>(QObjectPrivate::get(o: d_ptr->engine));
469 QScript::APIShim shim(p);
470 JSC::ExecState* exec = p->currentFrame;
471
472 PersistentIdentifier rv(p);
473 new (&rv.d) JSC::Identifier(exec, (JSC::UString::Rep *)id);
474 rv.identifier = (void *)((JSC::Identifier &)rv.d).ustring().rep();
475 return rv;
476}
477
478QString QScriptDeclarativeClass::toString(const Identifier &identifier)
479{
480 JSC::UString::Rep *r = (JSC::UString::Rep *)identifier;
481 return QString((QChar *)r->data(), r->size());
482}
483
484bool QScriptDeclarativeClass::startsWithUpper(const Identifier &identifier)
485{
486 JSC::UString::Rep *r = (JSC::UString::Rep *)identifier;
487 if (r->size() < 1)
488 return false;
489 return QChar::category(ucs4: (ushort)(r->data()[0])) == QChar::Letter_Uppercase;
490}
491
492quint32 QScriptDeclarativeClass::toArrayIndex(const Identifier &identifier, bool *ok)
493{
494 JSC::UString::Rep *r = (JSC::UString::Rep *)identifier;
495 JSC::UString s(r);
496 return s.toArrayIndex(ok);
497}
498
499QScriptClass::QueryFlags
500QScriptDeclarativeClass::queryProperty(Object *object, const Identifier &name,
501 QScriptClass::QueryFlags flags)
502{
503 Q_UNUSED(object);
504 Q_UNUSED(name);
505 Q_UNUSED(flags);
506 return {};
507}
508
509QScriptDeclarativeClass::Value
510QScriptDeclarativeClass::property(Object *object, const Identifier &name)
511{
512 Q_UNUSED(object);
513 Q_UNUSED(name);
514 return Value();
515}
516
517void QScriptDeclarativeClass::setProperty(Object *object, const Identifier &name,
518 const QScriptValue &value)
519{
520 Q_UNUSED(object);
521 Q_UNUSED(name);
522 Q_UNUSED(value);
523}
524
525QScriptValue::PropertyFlags
526QScriptDeclarativeClass::propertyFlags(Object *object, const Identifier &name)
527{
528 Q_UNUSED(object);
529 Q_UNUSED(name);
530 return {};
531}
532
533QScriptDeclarativeClass::Value QScriptDeclarativeClass::call(Object *object,
534 QScriptContext *ctxt)
535{
536 Q_UNUSED(object);
537 Q_UNUSED(ctxt);
538 return Value();
539}
540
541bool QScriptDeclarativeClass::compare(Object *o, Object *o2)
542{
543 return o == o2;
544}
545
546QStringList QScriptDeclarativeClass::propertyNames(Object *object)
547{
548 Q_UNUSED(object);
549 return QStringList();
550}
551
552bool QScriptDeclarativeClass::isQObject() const
553{
554 return false;
555}
556
557QObject *QScriptDeclarativeClass::toQObject(Object *, bool *ok)
558{
559 if (ok) *ok = false;
560 return 0;
561}
562
563QVariant QScriptDeclarativeClass::toVariant(Object *, bool *ok)
564{
565 if (ok) *ok = false;
566 return QVariant();
567}
568
569QScriptContext *QScriptDeclarativeClass::context() const
570{
571 return d_ptr->context;
572}
573
574/*!
575 Creates a scope object with a fixed set of undeletable properties.
576*/
577QScriptValue QScriptDeclarativeClass::newStaticScopeObject(
578 QScriptEngine *engine, int propertyCount, const QString *names,
579 const QScriptValue *values, const QScriptValue::PropertyFlags *flags)
580{
581 QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(q: engine);
582 QScript::APIShim shim(eng_p);
583 JSC::ExecState *exec = eng_p->currentFrame;
584 QScriptStaticScopeObject::PropertyInfo *props = new QScriptStaticScopeObject::PropertyInfo[propertyCount];
585 for (int i = 0; i < propertyCount; ++i) {
586 unsigned attribs = QScriptEnginePrivate::propertyFlagsToJSCAttributes(flags: flags[i]);
587 Q_ASSERT_X(attribs & JSC::DontDelete, Q_FUNC_INFO, "All properties must be undeletable");
588 JSC::Identifier id = JSC::Identifier(exec, names[i]);
589 JSC::JSValue jsval = eng_p->scriptValueToJSCValue(value: values[i]);
590 props[i] = QScriptStaticScopeObject::PropertyInfo(id, jsval, attribs);
591 }
592 QScriptValue result = eng_p->scriptValueFromJSCValue(value: new (exec)QScriptStaticScopeObject(eng_p->staticScopeObjectStructure,
593 propertyCount, props));
594 delete[] props;
595 return result;
596}
597
598/*!
599 Creates a static scope object that's initially empty, but to which new
600 properties can be added.
601*/
602QScriptValue QScriptDeclarativeClass::newStaticScopeObject(QScriptEngine *engine)
603{
604 QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(q: engine);
605 QScript::APIShim shim(eng_p);
606 return eng_p->scriptValueFromJSCValue(value: new (eng_p->currentFrame)QScriptStaticScopeObject(eng_p->staticScopeObjectStructure));
607}
608
609QT_END_NAMESPACE
610

source code of qtscript/src/script/bridge/qscriptdeclarativeclass.cpp