source: trunk/src/script/qscriptengine_p.cpp@ 82

Last change on this file since 82 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 89.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtScript module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qscriptengine_p.h"
43
44#ifndef QT_NO_SCRIPT
45
46#include "qscriptvalueimpl_p.h"
47#include "qscriptcontext_p.h"
48#include "qscriptmember_p.h"
49#include "qscriptobject_p.h"
50#include "qscriptlexer_p.h"
51#include "qscriptnodepool_p.h"
52#include "qscriptparser_p.h"
53#include "qscriptcompiler_p.h"
54#include "qscriptvalueiteratorimpl_p.h"
55#include "qscriptecmaglobal_p.h"
56#include "qscriptecmamath_p.h"
57#include "qscriptecmaarray_p.h"
58#include "qscriptextenumeration_p.h"
59#include "qscriptsyntaxchecker_p.h"
60#include "qscriptsyntaxcheckresult_p.h"
61#include "qscriptclass.h"
62#include "qscriptclass_p.h"
63#include "qscriptengineagent.h"
64
65#include <QtCore/QDate>
66#include <QtCore/QDateTime>
67#include <QtCore/QRegExp>
68#include <QtCore/QStringList>
69#include <QtCore/QVariant>
70
71#ifndef QT_NO_QOBJECT
72#include "qscriptextensioninterface.h"
73#include <QtCore/QDir>
74#include <QtCore/QFile>
75#include <QtCore/QFileInfo>
76#include <QtCore/QTextStream>
77#include <QtCore/QCoreApplication>
78#include <QtCore/QPluginLoader>
79#endif
80
81Q_DECLARE_METATYPE(QScriptValue)
82#ifndef QT_NO_QOBJECT
83Q_DECLARE_METATYPE(QObjectList)
84#endif
85Q_DECLARE_METATYPE(QList<int>)
86
87QT_BEGIN_NAMESPACE
88
89extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str);
90extern double qstrtod(const char *s00, char const **se, bool *ok);
91
92namespace QScript {
93
94QString numberToString(qsreal value)
95{
96 if (qIsNaN(value))
97 return QLatin1String("NaN");
98
99 else if (qIsInf(value))
100 return QLatin1String(value < 0 ? "-Infinity" : "Infinity");
101
102 else if (value == 0)
103 return QLatin1String("0");
104
105 QByteArray buf;
106 buf.reserve(80);
107
108 int decpt;
109 int sign;
110 char *result = 0;
111 (void) qdtoa(value, 0, 0, &decpt, &sign, 0, &result);
112
113 if (! result)
114 return QString();
115
116 else if (decpt <= 0 && decpt > -6) {
117
118 buf.fill('0', -decpt + 2 + sign);
119
120 if (sign) // fix the sign.
121 buf[0] = '-';
122
123 buf[sign + 1] = '.';
124 buf += result;
125 }
126
127 else {
128 if (sign)
129 buf += '-';
130
131 buf += result;
132 int length = buf.length() - sign;
133
134 if (decpt <= 21 && decpt > 0) {
135 if (length <= decpt)
136 buf += QByteArray().fill('0', decpt - length);
137 else
138 buf.insert(decpt + sign, '.');
139 }
140
141 else if (result[0] >= '0' && result[0] <= '9') {
142 if (length > 1)
143 buf.insert(1 + sign, '.');
144
145 buf += 'e';
146 buf += (decpt >= 0) ? '+' : '-';
147
148 int e = decpt - 1;
149
150 if (e < 0)
151 e = -e;
152
153 if (e >= 100)
154 buf += '0' + e / 100;
155
156 if (e >= 10)
157 buf += '0' + (e % 100) / 10;
158
159 buf += '0' + e % 10;
160 }
161 }
162
163 free(result);
164
165 return QString::fromLatin1(buf);
166}
167
168static int toDigit(char c)
169{
170 if ((c >= '0') && (c <= '9'))
171 return c - '0';
172 else if ((c >= 'a') && (c <= 'z'))
173 return 10 + c - 'a';
174 else if ((c >= 'A') && (c <= 'Z'))
175 return 10 + c - 'A';
176 return -1;
177}
178
179qsreal integerFromString(const char *buf, int size, int radix)
180{
181 if (size == 0)
182 return qSNaN();
183
184 qsreal sign = 1.0;
185 int i = 0;
186 if (buf[0] == '+') {
187 ++i;
188 } else if (buf[0] == '-') {
189 sign = -1.0;
190 ++i;
191 }
192
193 if (((size-i) >= 2) && (buf[i] == '0')) {
194 if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
195 && (radix < 34)) {
196 if ((radix != 0) && (radix != 16))
197 return 0;
198 radix = 16;
199 i += 2;
200 } else {
201 if (radix == 0) {
202 radix = 8;
203 ++i;
204 }
205 }
206 } else if (radix == 0) {
207 radix = 10;
208 }
209
210 int j = i;
211 for ( ; i < size; ++i) {
212 int d = toDigit(buf[i]);
213 if ((d == -1) || (d >= radix))
214 break;
215 }
216 qsreal result;
217 if (j == i) {
218 if (!qstrcmp(buf, "Infinity"))
219 result = qInf();
220 else
221 result = qSNaN();
222 } else {
223 result = 0;
224 qsreal multiplier = 1;
225 for (--i ; i >= j; --i, multiplier *= radix)
226 result += toDigit(buf[i]) * multiplier;
227 }
228 result *= sign;
229 return result;
230}
231
232qsreal integerFromString(const QString &str, int radix)
233{
234 QByteArray ba = str.trimmed().toUtf8();
235 return integerFromString(ba.constData(), ba.size(), radix);
236}
237
238qsreal numberFromString(const QString &repr)
239{
240 QString str = repr.trimmed();
241 if ((str.length() > 2) && (str.at(0) == QLatin1Char('0')) && (str.at(1).toUpper() == QLatin1Char('X')))
242 return integerFromString(str.mid(2), 16);
243 QByteArray latin1 = str.toLatin1();
244 const char *data = latin1.constData();
245 const char *eptr = 0;
246 qsreal result = qstrtod(data, &eptr, 0);
247 if (eptr == data) {
248 if (str == QLatin1String("Infinity"))
249 result = +qInf();
250 else if (str == QLatin1String("+Infinity"))
251 result = +qInf();
252 else if (str == QLatin1String("-Infinity"))
253 result = -qInf();
254 else if (str.isEmpty())
255 result = 0;
256 else
257 result = qSNaN();
258 } else if (eptr != (data + latin1.length())) {
259 result = qSNaN();
260 }
261 return result;
262}
263
264NodePool::NodePool(const QString &fileName, QScriptEnginePrivate *engine)
265 : m_fileName(fileName), m_engine(engine)
266{
267#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
268 m_id = engine->nextScriptId();
269#endif
270}
271
272NodePool::~NodePool()
273{
274 qDeleteAll(m_codeCache);
275 m_codeCache.clear();
276
277#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
278 m_engine->notifyScriptUnload(id());
279#endif
280}
281
282Code *NodePool::createCompiledCode(AST::Node *node, CompilationUnit &compilation)
283{
284 QHash<AST::Node*, Code*>::const_iterator it = m_codeCache.constFind(node);
285 if (it != m_codeCache.constEnd())
286 return it.value();
287
288 Code *code = new Code();
289 code->init(compilation, this);
290
291 m_codeCache.insert(node, code);
292 return code;
293}
294
295class EvalFunction : public QScriptFunction
296{
297public:
298 EvalFunction(QScriptEnginePrivate *)
299 { length = 1; }
300
301 virtual ~EvalFunction() {}
302
303 void evaluate(QScriptContextPrivate *context, const QString &contents,
304 int lineNo, const QString &fileName, bool calledFromScript)
305 {
306 QScriptEnginePrivate *eng_p = context->engine();
307
308 QExplicitlySharedDataPointer<NodePool> pool;
309 pool = new NodePool(fileName, eng_p);
310 eng_p->setNodePool(pool.data());
311
312 QString errorMessage;
313 int errorLineNumber;
314 AST::Node *program = eng_p->createAbstractSyntaxTree(
315 contents, lineNo, &errorMessage, &errorLineNumber);
316
317 eng_p->setNodePool(0);
318
319#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
320 eng_p->notifyScriptLoad(pool->id(), contents, fileName, lineNo);
321#endif
322
323 Code *code = 0;
324 if (program) {
325 Compiler compiler(eng_p);
326 compiler.setTopLevelCompiler(true);
327 CompilationUnit compilation = compiler.compile(program);
328 if (!compilation.isValid()) {
329 errorMessage = compilation.errorMessage();
330 errorLineNumber = compilation.errorLineNumber();
331 } else {
332 code = pool->createCompiledCode(program, compilation);
333 }
334 }
335
336 if (!code) {
337 context->errorLineNumber = errorLineNumber;
338 context->currentLine = errorLineNumber;
339#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
340 Code *oldCode = context->m_code;
341 Code dummy;
342 dummy.astPool = pool.data();
343 context->m_code = &dummy; // so agents get the script ID
344 bool wasEvaluating = eng_p->m_evaluating;
345 eng_p->m_evaluating = true;
346 eng_p->notifyFunctionEntry(context);
347#endif
348 context->throwError(QScriptContext::SyntaxError, errorMessage);
349#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
350 eng_p->notifyFunctionExit(context);
351 eng_p->m_evaluating = wasEvaluating;
352 context->m_code = oldCode;
353#endif
354 return;
355 }
356
357 if (calledFromScript) {
358 if (QScriptContextPrivate *pc = context->parentContext()) {
359 context->setActivationObject(pc->activationObject());
360 context->setThisObject(pc->thisObject());
361 context->m_scopeChain = pc->m_scopeChain;
362 }
363 }
364
365 const QScriptInstruction *iPtr = context->instructionPointer();
366 context->execute(code);
367 context->setInstructionPointer(iPtr);
368 }
369
370 virtual void execute(QScriptContextPrivate *context)
371 {
372 QScriptEnginePrivate *eng = context->engine();
373 int lineNo = context->currentLine;
374 if (lineNo == -1) {
375 QScriptContextPrivate *pc = context->parentContext();
376 if (pc)
377 lineNo = pc->currentLine;
378 else
379 lineNo = 1;
380 }
381 QString fileName; // don't set this for now, we don't want to change the official eval() for now.
382
383 if (context->argumentCount() == 0) {
384 context->setReturnValue(eng->undefinedValue());
385 } else {
386 QScriptValueImpl arg = context->argument(0);
387 if (arg.isString()) {
388 QString contents = arg.toString();
389 evaluate(context, contents, lineNo, fileName, /*calledFromScript=*/true);
390 } else {
391 context->setReturnValue(arg);
392 }
393 }
394 }
395
396 QString functionName() const
397 {
398 return QLatin1String("eval");
399 }
400};
401
402class ArgumentsClassData: public QScriptClassData
403{
404
405public:
406
407 static inline QScript::ArgumentsObjectData *get(const QScriptValueImpl &object)
408 { return static_cast<QScript::ArgumentsObjectData*>(object.objectData()); }
409
410 virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId,
411 QScript::Member *member, QScriptValueImpl *base,
412 QScript::AccessMode access);
413 virtual bool get(const QScriptValueImpl &object, const QScript::Member &member,
414 QScriptValueImpl *out_value);
415 virtual bool put(QScriptValueImpl *object, const QScript::Member &member,
416 const QScriptValueImpl &value);
417 virtual void mark(const QScriptValueImpl &object, int generation);
418 virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object);
419};
420
421class ArgumentsClassDataIterator: public QScriptClassDataIterator
422{
423public:
424 ArgumentsClassDataIterator(ArgumentsObjectData *data);
425 virtual ~ArgumentsClassDataIterator();
426
427 virtual bool hasNext() const;
428 virtual void next(QScript::Member *member);
429
430 virtual bool hasPrevious() const;
431 virtual void previous(QScript::Member *member);
432
433 virtual void toFront();
434 virtual void toBack();
435
436private:
437 ArgumentsObjectData *m_data;
438 uint m_pos;
439};
440
441bool ArgumentsClassData::resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId,
442 QScript::Member *member, QScriptValueImpl *base,
443 QScript::AccessMode /*access*/)
444{
445 QString propertyName = object.engine()->toString(nameId);
446 bool isNumber;
447 quint32 index = propertyName.toUInt(&isNumber);
448 if (isNumber) {
449 QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object);
450 if (index < data->length) {
451 member->native(/*nameId=*/0, index, QScriptValue::SkipInEnumeration);
452 *base = object;
453 return true;
454 }
455 }
456
457 return false;
458}
459
460bool ArgumentsClassData::get(const QScriptValueImpl &object, const QScript::Member &member,
461 QScriptValueImpl *out_value)
462{
463 QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object);
464 if (member.nameId() == 0) {
465 QScriptObject *activation_data = data->activation.objectValue();
466 *out_value = activation_data->m_values[member.id()];
467 return true;
468 }
469 return false;
470}
471
472bool ArgumentsClassData::put(QScriptValueImpl *object, const QScript::Member &member,
473 const QScriptValueImpl &value)
474{
475 Q_ASSERT(member.nameId() == 0);
476 QScript::ArgumentsObjectData *data = ArgumentsClassData::get(*object);
477 QScriptObject *activation_data = data->activation.objectValue();
478 activation_data->m_values[member.id()] = value;
479 return true;
480}
481
482void ArgumentsClassData::mark(const QScriptValueImpl &object, int generation)
483{
484 QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object);
485 data->activation.mark(generation);
486}
487
488QScriptClassDataIterator *ArgumentsClassData::newIterator(const QScriptValueImpl &object)
489{
490 QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object);
491 return new ArgumentsClassDataIterator(data);
492}
493
494ArgumentsClassDataIterator::ArgumentsClassDataIterator(ArgumentsObjectData *data)
495 : m_data(data), m_pos(0)
496{
497}
498
499ArgumentsClassDataIterator::~ArgumentsClassDataIterator()
500{
501}
502
503bool ArgumentsClassDataIterator::hasNext() const
504{
505 return m_pos < m_data->length;
506}
507
508void ArgumentsClassDataIterator::next(QScript::Member *member)
509{
510 if (m_pos == m_data->length) {
511 member->invalidate();
512 } else {
513 member->native(/*nameId=*/0, m_pos, QScriptValue::SkipInEnumeration);
514 ++m_pos;
515 }
516}
517
518bool ArgumentsClassDataIterator::hasPrevious() const
519{
520 return (m_pos != 0);
521}
522
523void ArgumentsClassDataIterator::previous(QScript::Member *member)
524{
525 if (m_pos == 0) {
526 member->invalidate();
527 } else {
528 --m_pos;
529 member->native(/*nameId=*/0, m_pos, QScriptValue::SkipInEnumeration);
530 }
531}
532
533void ArgumentsClassDataIterator::toFront()
534{
535 m_pos = 0;
536}
537
538void ArgumentsClassDataIterator::toBack()
539{
540 m_pos = m_data->length;
541}
542
543} // namespace QScript
544
545const qsreal QScriptEnginePrivate::D16 = 65536.0;
546const qsreal QScriptEnginePrivate::D32 = 4294967296.0;
547
548QScriptEnginePrivate::~QScriptEnginePrivate()
549{
550 while (!m_agents.isEmpty())
551 delete m_agents.takeFirst();
552
553 // invalidate values that we have references to
554 {
555 QHash<QScriptObject*, QScriptValuePrivate*>::const_iterator it;
556 for (it = m_objectHandles.constBegin(); it != m_objectHandles.constEnd(); ++it)
557 (*it)->invalidate();
558 }
559 {
560 QHash<QScriptNameIdImpl*, QScriptValuePrivate*>::const_iterator it;
561 for (it = m_stringHandles.constBegin(); it != m_stringHandles.constEnd(); ++it)
562 (*it)->invalidate();
563 }
564 {
565 QVector<QScriptValuePrivate*>::const_iterator it;
566 for (it = m_otherHandles.constBegin(); it != m_otherHandles.constEnd(); ++it)
567 (*it)->invalidate();
568 }
569
570 // invalidate interned strings that are known to the outside world
571 {
572 QHash<QScriptNameIdImpl*, QScriptStringPrivate*>::const_iterator it;
573 for (it = m_internedStrings.constBegin(); it != m_internedStrings.constEnd(); ++it)
574 it.value()->nameId = 0;
575 }
576
577 delete[] m_string_hash_base;
578 qDeleteAll(m_stringRepository);
579 qDeleteAll(m_tempStringRepository);
580
581 if (tempStackBegin)
582 delete[] tempStackBegin;
583
584#ifndef QT_NO_QOBJECT
585 deletePendingQObjects();
586 qDeleteAll(m_qobjectData);
587# ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
588 qDeleteAll(m_cachedMetaObjects);
589# endif
590#endif
591
592 qDeleteAll(m_allocated_classes);
593}
594
595QScript::AST::Node *QScriptEnginePrivate::changeAbstractSyntaxTree(QScript::AST::Node *prg)
596{
597 QScript::AST::Node *was = m_abstractSyntaxTree;
598 m_abstractSyntaxTree = prg;
599 return was;
600}
601
602QScript::AST::Node *QScriptEnginePrivate::createAbstractSyntaxTree(
603 const QString &source, int lineNumber, QString *errorMessage, int *errorLineNumber)
604{
605 QScript::Lexer lex(this);
606 setLexer(&lex);
607 lex.setCode(source, lineNumber);
608
609 QScriptParser parser;
610
611 if (! parser.parse(this)) {
612 if (errorMessage)
613 *errorMessage = parser.errorMessage();
614 if (errorLineNumber)
615 *errorLineNumber = parser.errorLineNumber();
616 return 0;
617 }
618
619 return abstractSyntaxTree();
620}
621
622void QScriptEnginePrivate::markObject(const QScriptValueImpl &object, int generation)
623{
624 QScriptObject *instance = object.objectValue();
625 QScript::GCBlock *block = QScript::GCBlock::get(instance);
626
627 enum { MAX_GC_DEPTH = 32 };
628
629 if (block->generation + 1 != generation)
630 return;
631
632 if (m_gc_depth >= MAX_GC_DEPTH) {
633 // do the marking later
634 m_markStack.append(object);
635 return;
636 }
637
638 ++block->generation;
639 ++m_gc_depth;
640
641 if (QScriptClassData *data = object.classInfo()->data())
642 data->mark(object, generation);
643
644 if (instance->m_prototype.isObject())
645 markObject(instance->m_prototype, generation);
646
647 if (instance->m_scope.isObject())
648 markObject(instance->m_scope, generation);
649
650 const QScriptValueImpl &internalValue = instance->m_internalValue;
651
652 if (internalValue.isValid()) {
653 if (internalValue.isObject())
654 markObject(internalValue, generation);
655
656 else if (internalValue.isString())
657 markString(internalValue.m_string_value, generation);
658 }
659
660 int garbage = 0;
661
662 for (int i = 0; i < instance->memberCount(); ++i) {
663 QScript::Member m;
664 instance->member(i, &m);
665
666 if (! m.isValid()) {
667 ++garbage;
668 continue;
669 }
670
671 Q_ASSERT(m.isObjectProperty());
672
673 QScriptValueImpl child;
674 instance->get(m, &child);
675
676 if (m.nameId())
677 markString(m.nameId(), generation);
678
679 if (! child.isValid())
680 continue;
681
682 else if (child.isObject())
683 markObject(child, generation);
684
685 else if (child.isString())
686 markString(child.m_string_value, generation);
687 }
688
689 --m_gc_depth;
690
691 if (garbage < 128) // ###
692 return;
693
694 int j = 0;
695 for (int i = 0; i < instance->memberCount(); ++i) {
696 QScript::Member m;
697 instance->member(i, &m);
698
699 if (! m.isValid())
700 continue;
701
702 if (i != j) {
703 instance->m_members[j].object(m.nameId(), j, m.flags());
704 instance->m_values[j] = instance->m_values[i];
705 }
706 ++j;
707 }
708 //qDebug() << "==> old:" << instance->m_members.size() << "new:" << j;
709 instance->m_members.resize(j);
710 instance->m_values.resize(j);
711}
712
713void QScriptEnginePrivate::markFrame(QScriptContextPrivate *context, int generation)
714{
715 QScriptValueImpl activation = context->activationObject();
716 QScriptValueImpl thisObject = context->thisObject();
717 QScriptValueImpl scopeChain = context->m_scopeChain;
718 QScriptValueImpl callee = context->m_callee;
719 QScriptValueImpl arguments = context->m_arguments;
720
721 if (activation.isObject())
722 markObject(activation, generation);
723
724 if (scopeChain.isObject())
725 markObject(scopeChain, generation);
726
727 if (thisObject.isObject())
728 markObject(thisObject, generation);
729
730 if (callee.isObject())
731 markObject(callee, generation);
732
733 if (arguments.isObject())
734 markObject(arguments, generation);
735
736 if (context->returnValue().isValid()) {
737 if (context->returnValue().isObject())
738 markObject(context->returnValue(), generation);
739
740 else if (context->returnValue().isString())
741 markString(context->returnValue().m_string_value, generation);
742 }
743
744 if (context->baseStackPointer() != context->currentStackPointer()) {
745 // mark the temp stack
746
747 for (const QScriptValueImpl *it = context->baseStackPointer(); it != (context->currentStackPointer() + 1); ++it) {
748 if (! it) {
749 qWarning() << "no temp stack!!!";
750 break;
751 }
752
753 else if (! it->isValid()) // ### assert?
754 continue;
755
756 else if (it->isObject())
757 markObject(*it, generation);
758
759 else if (it->isString())
760 markString(it->m_string_value, generation);
761 }
762 }
763}
764
765bool QScriptEnginePrivate::isCollecting() const
766{
767 return (m_gc_depth != -1) || objectAllocator.sweeping();
768}
769
770void QScriptEnginePrivate::maybeGC_helper(bool do_string_gc)
771{
772 // qDebug() << "==>" << objectAllocator.newAllocatedBlocks() << "free:" << objectAllocator.freeBlocks();
773 Q_ASSERT(m_gc_depth == -1);
774 ++m_gc_depth;
775
776 int generation = m_objectGeneration + 1;
777
778 markObject(m_globalObject, generation);
779
780 objectConstructor->mark(this, generation);
781 numberConstructor->mark(this, generation);
782 booleanConstructor->mark(this, generation);
783 stringConstructor->mark(this, generation);
784 dateConstructor->mark(this, generation);
785 functionConstructor->mark(this, generation);
786 arrayConstructor->mark(this, generation);
787 regexpConstructor->mark(this, generation);
788 errorConstructor->mark(this, generation);
789 enumerationConstructor->mark(this, generation);
790 variantConstructor->mark(this, generation);
791#ifndef QT_NO_QOBJECT
792 qobjectConstructor->mark(this, generation);
793 qmetaObjectConstructor->mark(this, generation);
794#endif
795
796 {
797 QScriptContextPrivate *current = currentContext();
798 while (current != 0) {
799 markFrame (current, generation);
800 current = current->parentContext();
801 }
802 }
803
804 {
805 QHash<QScriptObject*, QScriptValuePrivate*>::const_iterator it;
806 for (it = m_objectHandles.constBegin(); it != m_objectHandles.constEnd(); ++it)
807 markObject((*it)->value, generation);
808 }
809
810 {
811 QHash<QScriptNameIdImpl*, QScriptValuePrivate*>::const_iterator it;
812 for (it = m_stringHandles.constBegin(); it != m_stringHandles.constEnd(); ++it)
813 markString((*it)->value.stringValue(), generation);
814 }
815
816 {
817 QHash<int, QScriptCustomTypeInfo>::const_iterator it;
818 for (it = m_customTypes.constBegin(); it != m_customTypes.constEnd(); ++it)
819 (*it).prototype.mark(generation);
820 }
821
822#ifndef QT_NO_QOBJECT
823# ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
824 {
825 QHash<const QMetaObject*, QScriptMetaObject*>::const_iterator it;
826 for (it = m_cachedMetaObjects.constBegin(); it != m_cachedMetaObjects.constEnd(); ++it) {
827 {
828 QList<QScriptNameIdImpl*> memberNames = (*it)->registeredMemberNames();
829 QList<QScriptNameIdImpl*>::const_iterator it2;
830 for (it2 = memberNames.constBegin(); it2 != memberNames.constEnd(); ++it2)
831 markString(*it2, generation);
832 }
833 {
834 QList<QScriptValueImpl> propertyAccessors = (*it)->registeredPropertyAccessors();
835 QList<QScriptValueImpl>::const_iterator it2;
836 for (it2 = propertyAccessors.constBegin(); it2 != propertyAccessors.constEnd(); ++it2)
837 markObject(*it2, generation);
838 }
839 }
840 }
841# endif
842 processMarkStack(generation); // make sure everything is marked before marking qobject data
843 {
844 QHash<QObject*, QScriptQObjectData*>::const_iterator it;
845 for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
846 QScriptQObjectData *qdata = it.value();
847 qdata->mark(generation);
848 }
849 }
850#endif
851 processMarkStack(generation);
852
853 Q_ASSERT(m_gc_depth == 0);
854 --m_gc_depth;
855
856 objectAllocator.sweep(generation);
857
858 m_objectGeneration = generation;
859
860 //qDebug() << "free blocks:" << objectAllocator.freeBlocks();
861
862#ifndef QT_NO_QOBJECT
863 deletePendingQObjects();
864#endif
865
866 if (! do_string_gc)
867 return;
868
869 {
870 QHash<QScriptNameIdImpl*, QScriptStringPrivate*>::const_iterator it;
871 for (it = m_internedStrings.constBegin(); it != m_internedStrings.constEnd(); ++it) {
872 it.value()->nameId->used = true;
873 }
874 }
875
876#if 0
877 qDebug() << "do_string_gc:" << do_string_gc
878 << ((m_stringRepository.size() - m_oldStringRepositorySize) > 256)
879 << ((m_tempStringRepository.size() - m_oldTempStringRepositorySize) > 2048);
880#endif
881
882 QVector<QScriptNameIdImpl*> compressed;
883 compressed.reserve(m_stringRepository.size());
884
885 for (int i = 0; i < m_stringRepository.size(); ++i) {
886 QScriptNameIdImpl *entry = m_stringRepository.at(i);
887
888 if (entry->used || entry->persistent) {
889 compressed.append(entry);
890 entry->used = false;
891 }
892
893 else {
894 //qDebug() << "deleted unique:" << entry->s;
895 delete entry;
896 }
897 }
898
899 // qDebug() << "before:" << m_stringRepository.size() << "after:" << compressed.size() << globalObject.objectValue()->m_members.size();
900 m_stringRepository = compressed;
901 rehashStringRepository(/*resize=*/ false);
902 m_oldStringRepositorySize = m_stringRepository.size();
903 m_newAllocatedStringRepositoryChars = 0;
904
905 compressed.clear();
906 for (int i = 0; i < m_tempStringRepository.size(); ++i) {
907 QScriptNameIdImpl *entry = m_tempStringRepository.at(i);
908
909 if (entry->used || entry->persistent) {
910 compressed.append(entry);
911 entry->used = false;
912 }
913
914 else {
915 //qDebug() << "deleted:" << entry->s;
916 delete entry;
917 }
918 }
919
920 //qDebug() << "before:" << m_tempStringRepository.size() << "after:" << compressed.size();
921
922 m_tempStringRepository = compressed;
923 m_oldTempStringRepositorySize = m_tempStringRepository.size();
924 m_newAllocatedTempStringRepositoryChars = 0;
925}
926
927void QScriptEnginePrivate::processMarkStack(int generation)
928{
929 // mark the objects we couldn't process due to recursion depth
930 while (!m_markStack.isEmpty())
931 markObject(m_markStack.takeLast(), generation);
932}
933
934void QScriptEnginePrivate::evaluate(QScriptContextPrivate *context, const QString &contents, int lineNumber, const QString &fileName)
935{
936 // ### try to remove cast
937 QScript::EvalFunction *evalFunction = static_cast<QScript::EvalFunction*>(m_evalFunction);
938 evalFunction->evaluate(context, contents, lineNumber, fileName, /*calledFromScript=*/ false);
939}
940
941qsreal QScriptEnginePrivate::convertToNativeDouble_helper(const QScriptValueImpl &value)
942{
943 switch (value.type()) {
944 case QScript::InvalidType:
945 Q_ASSERT(value.isValid());
946 break;
947
948 case QScript::UndefinedType:
949 case QScript::PointerType:
950 break;
951
952 case QScript::NullType:
953 return 0;
954
955 case QScript::BooleanType:
956 return value.m_bool_value;
957
958 case QScript::IntegerType:
959 case QScript::ReferenceType:
960 return value.m_int_value;
961
962 case QScript::NumberType:
963 return value.m_number_value;
964
965 case QScript::StringType:
966 return QScript::numberFromString(toString(value.m_string_value));
967
968 case QScript::ObjectType: {
969 QScriptValueImpl p = value.engine()->toPrimitive(value, QScriptValueImpl::NumberTypeHint);
970 if (! p.isValid() || p.isObject())
971 break;
972
973 return convertToNativeDouble(p);
974 }
975
976 case QScript::LazyStringType:
977 return QScript::numberFromString(*value.m_lazy_string_value);
978
979 } // switch
980
981 return qSNaN();
982}
983
984bool QScriptEnginePrivate::convertToNativeBoolean_helper(const QScriptValueImpl &value)
985{
986 switch (value.type()) {
987 case QScript::InvalidType:
988 Q_ASSERT(value.isValid());
989 return false;
990
991 case QScript::UndefinedType:
992 case QScript::PointerType:
993 case QScript::NullType:
994 case QScript::ReferenceType:
995 return false;
996
997 case QScript::BooleanType:
998 return value.m_bool_value;
999
1000 case QScript::IntegerType:
1001 return value.m_int_value != 0;
1002
1003 case QScript::NumberType:
1004 return value.m_number_value != 0 && !qIsNaN(value.m_number_value);
1005
1006 case QScript::StringType:
1007 return toString(value.m_string_value).length() != 0;
1008
1009 case QScript::ObjectType:
1010 return true;
1011
1012 case QScript::LazyStringType:
1013 return value.m_lazy_string_value->length() != 0;
1014
1015 } // switch
1016
1017 return false;
1018}
1019
1020QString QScriptEnginePrivate::convertToNativeString_helper(const QScriptValueImpl &value)
1021{
1022 static QStringList predefined;
1023 if (predefined.isEmpty()) {
1024 predefined.append(QString::fromLatin1("undefined"));
1025 predefined.append(QString::fromLatin1("null"));
1026 predefined.append(QString::fromLatin1("true"));
1027 predefined.append(QString::fromLatin1("false"));
1028 predefined.append(QString::fromLatin1("pointer"));
1029 }
1030
1031 switch (value.type()) {
1032 case QScript::InvalidType:
1033 Q_ASSERT(value.isValid());
1034 return QString();
1035
1036 case QScript::UndefinedType:
1037 return predefined.at(0);
1038
1039 case QScript::NullType:
1040 return predefined.at(1);
1041
1042 case QScript::BooleanType:
1043 return value.m_bool_value ? predefined.at(2) : predefined.at(3);
1044
1045 case QScript::IntegerType:
1046 return QString::number(value.m_int_value);
1047
1048 case QScript::NumberType:
1049 return QScript::numberToString(value.m_number_value);
1050
1051 case QScript::PointerType:
1052 return predefined.at(4);
1053
1054 case QScript::StringType:
1055 return toString(value.m_string_value);
1056
1057 case QScript::ReferenceType:
1058 return QString();
1059
1060 case QScript::ObjectType: {
1061 QScriptValueImpl p = value.engine()->toPrimitive(value, QScriptValueImpl::StringTypeHint);
1062
1063 if (!p.isValid() || strictlyEquals(p, value))
1064 return p.classInfo()->name();
1065
1066 return convertToNativeString(p);
1067 }
1068
1069 case QScript::LazyStringType:
1070 return *value.m_lazy_string_value;
1071
1072 } // switch
1073
1074 return QString();
1075}
1076
1077QScriptValueImpl QScriptEnginePrivate::toObject_helper(const QScriptValueImpl &value)
1078{
1079 QScriptValueImpl result;
1080 switch (value.type()) {
1081 case QScript::BooleanType:
1082 booleanConstructor->newBoolean(&result, value.m_bool_value);
1083 break;
1084
1085 case QScript::NumberType:
1086 numberConstructor->newNumber(&result, value.m_number_value);
1087 break;
1088
1089 case QScript::StringType:
1090 stringConstructor->newString(&result, value.m_string_value->s);
1091 break;
1092
1093 case QScript::LazyStringType:
1094 stringConstructor->newString(&result, *value.m_lazy_string_value);
1095 break;
1096
1097 case QScript::InvalidType:
1098 case QScript::UndefinedType:
1099 case QScript::NullType:
1100 case QScript::IntegerType:
1101 case QScript::ReferenceType:
1102 case QScript::PointerType:
1103 case QScript::ObjectType:
1104 break;
1105 } // switch
1106
1107 return result;
1108}
1109
1110// [[defaultValue]]
1111QScriptValueImpl QScriptEnginePrivate::toPrimitive_helper(const QScriptValueImpl &object,
1112 QScriptValueImpl::TypeHint hint)
1113{
1114 QScriptNameIdImpl *functionIds[2];
1115
1116 if ((hint == QScriptValueImpl::NumberTypeHint)
1117 || (hint == QScriptValueImpl::NoTypeHint
1118 && object.classInfo() != dateConstructor->classInfo())) {
1119 functionIds[0] = idTable()->id_valueOf;
1120 functionIds[1] = idTable()->id_toString;
1121 } else {
1122 functionIds[0] = idTable()->id_toString;
1123 functionIds[1] = idTable()->id_valueOf;
1124 }
1125
1126 for (int i = 0; i < 2; ++i) {
1127 QScriptValueImpl base;
1128 QScript::Member member;
1129
1130 if (! object.resolve(functionIds[i], &member, &base, QScriptValue::ResolvePrototype, QScript::Read))
1131 return object;
1132
1133 QScriptValueImpl f_valueOf;
1134 base.get(member, &f_valueOf);
1135
1136 if (QScriptFunction *foo = convertToNativeFunction(f_valueOf)) {
1137 QScriptContextPrivate *me = pushContext();
1138 QScriptValueImpl activation;
1139 newActivation(&activation);
1140 if (f_valueOf.scope().isValid())
1141 activation.setScope(f_valueOf.scope());
1142 else
1143 activation.setScope(m_globalObject);
1144 me->setActivationObject(activation);
1145 me->setThisObject(object);
1146 me->m_callee = f_valueOf;
1147 foo->execute(me);
1148 QScriptValueImpl result = me->returnValue();
1149 bool exception = (me->state() == QScriptContext::ExceptionState);
1150 popContext();
1151 if (exception || (result.isValid() && !result.isObject()))
1152 return result;
1153 }
1154 }
1155
1156 return object;
1157}
1158
1159void QScriptEnginePrivate::rehashStringRepository(bool resize)
1160{
1161 if (resize) {
1162 delete[] m_string_hash_base;
1163 m_string_hash_size <<= 1; // ### use primes
1164
1165 m_string_hash_base = new QScriptNameIdImpl* [m_string_hash_size];
1166 }
1167
1168 memset(m_string_hash_base, 0, sizeof(QScriptNameIdImpl*) * m_string_hash_size);
1169
1170 for (int index = 0; index < m_stringRepository.size(); ++index) {
1171 QScriptNameIdImpl *entry = m_stringRepository.at(index);
1172 uint h = _q_scriptHash(entry->s) % m_string_hash_size;
1173 entry->h = h;
1174 entry->next = m_string_hash_base[h];
1175 m_string_hash_base[h] = entry;
1176 }
1177}
1178
1179QScriptNameIdImpl *QScriptEnginePrivate::insertStringEntry(const QString &s)
1180{
1181 QScriptNameIdImpl *entry = new QScriptNameIdImpl(s);
1182 entry->unique = true;
1183 m_stringRepository.append(entry);
1184 m_newAllocatedStringRepositoryChars += s.length();
1185
1186 uint h = _q_scriptHash(s) % m_string_hash_size;
1187 entry->h = h;
1188 entry->next = m_string_hash_base[h];
1189 m_string_hash_base[h] = entry;
1190
1191 if (m_stringRepository.count() == m_string_hash_size)
1192 rehashStringRepository();
1193
1194 return entry;
1195}
1196
1197QScriptValueImpl QScriptEnginePrivate::call(const QScriptValueImpl &callee,
1198 const QScriptValueImpl &thisObject,
1199 const QScriptValueImplList &args,
1200 bool asConstructor)
1201{
1202 QScriptFunction *function = callee.toFunction();
1203 Q_ASSERT(function);
1204
1205 if (++m_callDepth == m_maxCallDepth) {
1206 QScriptContextPrivate *ctx_p = currentContext();
1207 return ctx_p->throwError(QLatin1String("call stack overflow"));
1208 }
1209
1210 QScriptContextPrivate *nested = pushContext();
1211 // set up the temp stack
1212 if (! nested->tempStack)
1213 nested->stackPtr = nested->tempStack = tempStackBegin;
1214
1215 newActivation(&nested->m_activation);
1216 if (callee.m_object_value->m_scope.isValid())
1217 nested->m_activation.m_object_value->m_scope = callee.m_object_value->m_scope;
1218 else
1219 nested->m_activation.m_object_value->m_scope = m_globalObject;
1220
1221 QScriptObject *activation_data = nested->m_activation.m_object_value;
1222
1223 int formalCount = function->formals.count();
1224 int argc = args.count();
1225 int mx = qMax(formalCount, argc);
1226 activation_data->m_members.resize(mx);
1227 activation_data->m_values.resize(mx);
1228 for (int i = 0; i < mx; ++i) {
1229 QScriptNameIdImpl *nameId = 0;
1230 if (i < formalCount)
1231 nameId = function->formals.at(i);
1232
1233 activation_data->m_members[i].object(nameId, i, QScriptValue::SkipInEnumeration);
1234 QScriptValueImpl arg = (i < argc) ? args.at(i) : m_undefinedValue;
1235 if (arg.isValid() && arg.engine() && (arg.engine() != this)) {
1236 qWarning("QScriptValue::call() failed: "
1237 "cannot call function with argument created in "
1238 "a different engine");
1239 popContext();
1240 return QScriptValueImpl();
1241 }
1242 activation_data->m_values[i] = arg.isValid() ? arg : m_undefinedValue;
1243 }
1244
1245 nested->argc = argc;
1246 QVector<QScriptValueImpl> argsv = args.toVector();
1247 nested->args = const_cast<QScriptValueImpl*> (argsv.constData());
1248
1249 if (thisObject.isObject())
1250 nested->m_thisObject = thisObject;
1251 else
1252 nested->m_thisObject = m_globalObject;
1253 nested->m_callee = callee;
1254 nested->m_calledAsConstructor = asConstructor;
1255
1256 nested->m_result = m_undefinedValue;
1257 function->execute(nested);
1258 --m_callDepth;
1259 QScriptValueImpl result = nested->m_result;
1260 nested->args = 0;
1261 popContext();
1262
1263 return result;
1264}
1265
1266QScriptValueImpl QScriptEnginePrivate::call(const QScriptValueImpl &callee,
1267 const QScriptValueImpl &thisObject,
1268 const QScriptValueImpl &args,
1269 bool asConstructor)
1270{
1271 QScriptValueImplList argsList;
1272 if (QScript::Ecma::Array::Instance *arr = arrayConstructor->get(args)) {
1273 QScript::Array actuals = arr->value;
1274 for (quint32 i = 0; i < actuals.count(); ++i) {
1275 QScriptValueImpl a = actuals.at(i);
1276 if (! a.isValid())
1277 argsList << undefinedValue();
1278 else
1279 argsList << a;
1280 }
1281 } else if (args.classInfo() == m_class_arguments) {
1282 QScript::ArgumentsObjectData *arguments;
1283 arguments = static_cast<QScript::ArgumentsObjectData*> (args.objectData());
1284 QScriptObject *activation = arguments->activation.objectValue();
1285 for (uint i = 0; i < arguments->length; ++i)
1286 argsList << activation->m_values[i];
1287 } else if (!(args.isUndefined() || args.isNull())) {
1288 return currentContext()->throwError(
1289 QScriptContext::TypeError,
1290 QLatin1String("QScriptValue::call(): arguments must be an array"));
1291 }
1292 return call(callee, thisObject, argsList, asConstructor);
1293}
1294
1295QScriptValueImpl QScriptEnginePrivate::arrayFromStringList(const QStringList &lst)
1296{
1297 QScriptValueImpl arr = newArray(lst.size());
1298 for (int i = 0; i < lst.size(); ++i)
1299 arr.setProperty(i, QScriptValueImpl(this, lst.at(i)));
1300 return arr;
1301}
1302
1303QStringList QScriptEnginePrivate::stringListFromArray(const QScriptValueImpl &arr)
1304{
1305 QStringList lst;
1306 uint len = arr.property(QLatin1String("length")).toUInt32();
1307 for (uint i = 0; i < len; ++i)
1308 lst.append(arr.property(i).toString());
1309 return lst;
1310}
1311
1312QScriptValueImpl QScriptEnginePrivate::arrayFromVariantList(const QVariantList &lst)
1313{
1314 QScriptValueImpl arr = newArray(lst.size());
1315 for (int i = 0; i < lst.size(); ++i)
1316 arr.setProperty(i, valueFromVariant(lst.at(i)));
1317 return arr;
1318}
1319
1320QVariantList QScriptEnginePrivate::variantListFromArray(const QScriptValueImpl &arr)
1321{
1322 QVariantList lst;
1323 uint len = arr.property(QLatin1String("length")).toUInt32();
1324 for (uint i = 0; i < len; ++i)
1325 lst.append(arr.property(i).toVariant());
1326 return lst;
1327}
1328
1329QScriptValueImpl QScriptEnginePrivate::objectFromVariantMap(const QVariantMap &vmap)
1330{
1331 QScriptValueImpl obj = newObject();
1332 QVariantMap::const_iterator it;
1333 for (it = vmap.constBegin(); it != vmap.constEnd(); ++it)
1334 obj.setProperty(it.key(), valueFromVariant(it.value()));
1335 return obj;
1336}
1337
1338QVariantMap QScriptEnginePrivate::variantMapFromObject(const QScriptValueImpl &obj)
1339{
1340 QVariantMap vmap;
1341 QScriptValueIteratorImpl it(obj);
1342 while (it.hasNext()) {
1343 it.next();
1344 vmap.insert(it.name(), it.value().toVariant());
1345 }
1346 return vmap;
1347}
1348
1349QScriptValueImpl QScriptEnginePrivate::create(int type, const void *ptr)
1350{
1351 Q_Q(QScriptEngine);
1352 Q_ASSERT(ptr);
1353 QScriptValueImpl result;
1354 QScriptCustomTypeInfo info = m_customTypes.value(type);
1355 if (info.marshal) {
1356 result = toImpl(info.marshal(q, ptr));
1357 } else {
1358 // check if it's one of the types we know
1359 switch (QMetaType::Type(type)) {
1360 case QMetaType::Void:
1361 result = m_undefinedValue;
1362 break;
1363 case QMetaType::Bool:
1364 result = QScriptValueImpl(*reinterpret_cast<const bool*>(ptr));
1365 break;
1366 case QMetaType::Int:
1367 result = QScriptValueImpl(*reinterpret_cast<const int*>(ptr));
1368 break;
1369 case QMetaType::UInt:
1370 result = QScriptValueImpl(*reinterpret_cast<const uint*>(ptr));
1371 break;
1372 case QMetaType::LongLong:
1373 result = QScriptValueImpl(qsreal(*reinterpret_cast<const qlonglong*>(ptr)));
1374 break;
1375 case QMetaType::ULongLong:
1376#if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804
1377#pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.")
1378 result = QScriptValueImpl(qsreal((qlonglong)*reinterpret_cast<const qulonglong*>(ptr)));
1379#elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
1380 result = QScriptValueImpl(qsreal((qlonglong)*reinterpret_cast<const qulonglong*>(ptr)));
1381#else
1382 result = QScriptValueImpl(qsreal(*reinterpret_cast<const qulonglong*>(ptr)));
1383#endif
1384 break;
1385 case QMetaType::Double:
1386 result = QScriptValueImpl(*reinterpret_cast<const double*>(ptr));
1387 break;
1388 case QMetaType::QString:
1389 result = QScriptValueImpl(this, *reinterpret_cast<const QString*>(ptr));
1390 break;
1391 case QMetaType::Float:
1392 result = QScriptValueImpl(*reinterpret_cast<const float*>(ptr));
1393 break;
1394 case QMetaType::Short:
1395 result = QScriptValueImpl(*reinterpret_cast<const short*>(ptr));
1396 break;
1397 case QMetaType::UShort:
1398 result = QScriptValueImpl(*reinterpret_cast<const unsigned short*>(ptr));
1399 break;
1400 case QMetaType::Char:
1401 result = QScriptValueImpl(*reinterpret_cast<const char*>(ptr));
1402 break;
1403 case QMetaType::UChar:
1404 result = QScriptValueImpl(*reinterpret_cast<const unsigned char*>(ptr));
1405 break;
1406 case QMetaType::QChar:
1407 result = QScriptValueImpl((*reinterpret_cast<const QChar*>(ptr)).unicode());
1408 break;
1409 case QMetaType::QStringList:
1410 result = arrayFromStringList(*reinterpret_cast<const QStringList *>(ptr));
1411 break;
1412 case QMetaType::QVariantList:
1413 result = arrayFromVariantList(*reinterpret_cast<const QVariantList *>(ptr));
1414 break;
1415 case QMetaType::QVariantMap:
1416 result = objectFromVariantMap(*reinterpret_cast<const QVariantMap *>(ptr));
1417 break;
1418 case QMetaType::QDateTime: {
1419 QDateTime dateTime = *reinterpret_cast<const QDateTime *>(ptr);
1420 dateConstructor->newDate(&result, dateTime);
1421 } break;
1422 case QMetaType::QDate: {
1423 QDate date = *reinterpret_cast<const QDate *>(ptr);
1424 dateConstructor->newDate(&result, date);
1425 } break;
1426#ifndef QT_NO_REGEXP
1427 case QMetaType::QRegExp: {
1428 QRegExp rx = *reinterpret_cast<const QRegExp *>(ptr);
1429 regexpConstructor->newRegExp(&result, rx);
1430 } break;
1431#endif
1432#ifndef QT_NO_QOBJECT
1433 case QMetaType::QObjectStar:
1434 case QMetaType::QWidgetStar:
1435 newQObject(&result, *reinterpret_cast<QObject* const *>(ptr));
1436 break;
1437#endif
1438 default:
1439 if (type == qMetaTypeId<QScriptValue>()) {
1440 result = toImpl(*reinterpret_cast<const QScriptValue*>(ptr));
1441 if (!result.isValid())
1442 result = m_undefinedValue;
1443 }
1444
1445#ifndef QT_NO_QOBJECT
1446 // lazy registration of some common list types
1447 else if (type == qMetaTypeId<QObjectList>()) {
1448 qScriptRegisterSequenceMetaType<QObjectList>(q);
1449 return create(type, ptr);
1450 }
1451#endif
1452 else if (type == qMetaTypeId<QList<int> >()) {
1453 qScriptRegisterSequenceMetaType<QList<int> >(q);
1454 return create(type, ptr);
1455 }
1456
1457 else {
1458 QByteArray typeName = QMetaType::typeName(type);
1459 if (typeName == "QVariant")
1460 result = valueFromVariant(*reinterpret_cast<const QVariant*>(ptr));
1461 else if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(ptr))
1462 result = nullValue();
1463 else
1464 newVariant(&result, QVariant(type, ptr));
1465 }
1466 }
1467 }
1468 if (result.isObject() && info.prototype.isValid()
1469 && strictlyEquals(result.prototype(), objectConstructor->publicPrototype)) {
1470 result.setPrototype(info.prototype);
1471 }
1472 return result;
1473}
1474
1475bool QScriptEnginePrivate::convert(const QScriptValueImpl &value,
1476 int type, void *ptr,
1477 QScriptEnginePrivate *eng)
1478{
1479 if (!eng)
1480 eng = value.engine();
1481 if (eng) {
1482 QScriptCustomTypeInfo info = eng->m_customTypes.value(type);
1483 if (info.demarshal) {
1484 info.demarshal(eng->toPublic(value), ptr);
1485 return true;
1486 }
1487 }
1488
1489 // check if it's one of the types we know
1490 switch (QMetaType::Type(type)) {
1491 case QMetaType::Bool:
1492 *reinterpret_cast<bool*>(ptr) = value.toBoolean();
1493 return true;
1494 case QMetaType::Int:
1495 *reinterpret_cast<int*>(ptr) = value.toInt32();
1496 return true;
1497 case QMetaType::UInt:
1498 *reinterpret_cast<uint*>(ptr) = value.toUInt32();
1499 return true;
1500 case QMetaType::LongLong:
1501 *reinterpret_cast<qlonglong*>(ptr) = qlonglong(value.toInteger());
1502 return true;
1503 case QMetaType::ULongLong:
1504 *reinterpret_cast<qulonglong*>(ptr) = qulonglong(value.toInteger());
1505 return true;
1506 case QMetaType::Double:
1507 *reinterpret_cast<double*>(ptr) = value.toNumber();
1508 return true;
1509 case QMetaType::QString:
1510 if (value.isUndefined() || value.isNull())
1511 *reinterpret_cast<QString*>(ptr) = QString();
1512 else
1513 *reinterpret_cast<QString*>(ptr) = value.toString();
1514 return true;
1515 case QMetaType::Float:
1516 *reinterpret_cast<float*>(ptr) = value.toNumber();
1517 return true;
1518 case QMetaType::Short:
1519 *reinterpret_cast<short*>(ptr) = short(value.toInt32());
1520 return true;
1521 case QMetaType::UShort:
1522 *reinterpret_cast<unsigned short*>(ptr) = value.toUInt16();
1523 return true;
1524 case QMetaType::Char:
1525 *reinterpret_cast<char*>(ptr) = char(value.toInt32());
1526 return true;
1527 case QMetaType::UChar:
1528 *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(value.toInt32());
1529 return true;
1530 case QMetaType::QChar:
1531 if (value.isString()) {
1532 QString str = value.toString();
1533 *reinterpret_cast<QChar*>(ptr) = str.isEmpty() ? QChar() : str.at(0);
1534 } else {
1535 *reinterpret_cast<QChar*>(ptr) = QChar(value.toUInt16());
1536 }
1537 return true;
1538 case QMetaType::QDateTime:
1539 if (value.isDate()) {
1540 *reinterpret_cast<QDateTime *>(ptr) = value.toDateTime();
1541 return true;
1542 } break;
1543 case QMetaType::QDate:
1544 if (value.isDate()) {
1545 *reinterpret_cast<QDate *>(ptr) = value.toDateTime().date();
1546 return true;
1547 } break;
1548#ifndef QT_NO_REGEXP
1549 case QMetaType::QRegExp:
1550 if (value.isRegExp()) {
1551 *reinterpret_cast<QRegExp *>(ptr) = value.toRegExp();
1552 return true;
1553 } break;
1554#endif
1555#ifndef QT_NO_QOBJECT
1556 case QMetaType::QObjectStar:
1557 if (value.isQObject() || value.isNull()) {
1558 *reinterpret_cast<QObject* *>(ptr) = value.toQObject();
1559 return true;
1560 } break;
1561 case QMetaType::QWidgetStar:
1562 if (value.isQObject() || value.isNull()) {
1563 QObject *qo = value.toQObject();
1564 if (!qo || qo->isWidgetType()) {
1565 *reinterpret_cast<QWidget* *>(ptr) = reinterpret_cast<QWidget*>(qo);
1566 return true;
1567 }
1568 } break;
1569#endif
1570 case QMetaType::QStringList:
1571 if (value.isArray()) {
1572 *reinterpret_cast<QStringList *>(ptr) = stringListFromArray(value);
1573 return true;
1574 } break;
1575 case QMetaType::QVariantList:
1576 if (value.isArray()) {
1577 *reinterpret_cast<QVariantList *>(ptr) = variantListFromArray(value);
1578 return true;
1579 } break;
1580 case QMetaType::QVariantMap:
1581 if (value.isObject()) {
1582 *reinterpret_cast<QVariantMap *>(ptr) = variantMapFromObject(value);
1583 return true;
1584 } break;
1585 default:
1586 ;
1587 }
1588
1589 QByteArray name = QMetaType::typeName(type);
1590#ifndef QT_NO_QOBJECT
1591 if (convertToNativeQObject(value, name, reinterpret_cast<void* *>(ptr)))
1592 return true;
1593#endif
1594 if (value.isVariant() && name.endsWith('*')) {
1595 int valueType = QMetaType::type(name.left(name.size()-1));
1596 QVariant &var = value.variantValue();
1597 if (valueType == var.userType()) {
1598 *reinterpret_cast<void* *>(ptr) = var.data();
1599 return true;
1600 } else {
1601 // look in the prototype chain
1602 QScriptValueImpl proto = value.prototype();
1603 while (proto.isObject()) {
1604 bool canCast = false;
1605 if (proto.isVariant()) {
1606 canCast = (type == proto.variantValue().userType())
1607 || (valueType && (valueType == proto.variantValue().userType()));
1608 }
1609#ifndef QT_NO_QOBJECT
1610 else if (proto.isQObject()) {
1611 QByteArray className = name.left(name.size()-1);
1612 if (QObject *qobject = proto.toQObject())
1613 canCast = qobject->qt_metacast(className) != 0;
1614 }
1615#endif
1616 if (canCast) {
1617 QByteArray varTypeName = QMetaType::typeName(var.userType());
1618 if (varTypeName.endsWith('*'))
1619 *reinterpret_cast<void* *>(ptr) = *reinterpret_cast<void* *>(var.data());
1620 else
1621 *reinterpret_cast<void* *>(ptr) = var.data();
1622 return true;
1623 }
1624 proto = proto.prototype();
1625 }
1626 }
1627 } else if (value.isNull() && name.endsWith('*')) {
1628 *reinterpret_cast<void* *>(ptr) = 0;
1629 return true;
1630 } else if (type == qMetaTypeId<QScriptValue>()) {
1631 if (!eng)
1632 return false;
1633 *reinterpret_cast<QScriptValue*>(ptr) = eng->toPublic(value);
1634 return true;
1635 } else if (name == "QVariant") {
1636 *reinterpret_cast<QVariant*>(ptr) = value.toVariant();
1637 return true;
1638 }
1639
1640 // lazy registration of some common list types
1641#ifndef QT_NO_QOBJECT
1642 else if (type == qMetaTypeId<QObjectList>()) {
1643 if (!eng)
1644 return false;
1645 qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
1646 return convert(value, type, ptr, eng);
1647 }
1648#endif
1649 else if (type == qMetaTypeId<QList<int> >()) {
1650 if (!eng)
1651 return false;
1652 qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
1653 return convert(value, type, ptr, eng);
1654 }
1655
1656#if 0
1657 if (!name.isEmpty()) {
1658 qWarning("QScriptEngine::convert: unable to convert value to type `%s'",
1659 name.constData());
1660 }
1661#endif
1662 return false;
1663}
1664
1665QScriptValuePrivate *QScriptEnginePrivate::registerValue(const QScriptValueImpl &value)
1666{
1667 if (value.isString()) {
1668 QScriptNameIdImpl *id = value.stringValue();
1669 QScriptValuePrivate *p = m_stringHandles.value(id);
1670 if (p)
1671 return p;
1672 p = m_handleRepository.get();
1673 p->engine = q_func();
1674 p->value = value;
1675 m_stringHandles.insert(id, p);
1676 return p;
1677 } else if (value.isObject()) {
1678 QScriptObject *instance = value.objectValue();
1679 QScriptValuePrivate *p = m_objectHandles.value(instance);
1680 if (p)
1681 return p;
1682 p = m_handleRepository.get();
1683 p->engine = q_func();
1684 p->value = value;
1685 m_objectHandles.insert(instance, p);
1686 return p;
1687 }
1688 QScriptValuePrivate *p = m_handleRepository.get();
1689 p->engine = q_func();
1690 p->value = value;
1691 m_otherHandles.append(p);
1692 return p;
1693}
1694
1695QScriptEnginePrivate::QScriptEnginePrivate()
1696{
1697 m_undefinedValue = QScriptValueImpl(QScriptValue::UndefinedValue);
1698 m_nullValue = QScriptValueImpl(QScriptValue::NullValue);
1699
1700 m_evaluating = false;
1701 m_abort = false;
1702 m_callDepth = 0;
1703#if defined(Q_OS_WIN)
1704 m_maxCallDepth = 88;
1705#elif defined(Q_OS_MAC)
1706 m_maxCallDepth = 640;
1707#elif defined(QT_ARCH_ARM) || defined(QT_ARCH_ARMV6)
1708 m_maxCallDepth = 360;
1709#else
1710 m_maxCallDepth = 512;
1711#endif
1712 m_oldStringRepositorySize = 0;
1713 m_oldTempStringRepositorySize = 0;
1714 m_newAllocatedStringRepositoryChars = 0;
1715 m_newAllocatedTempStringRepositoryChars = 0;
1716 m_context = 0;
1717 m_abstractSyntaxTree = 0;
1718 m_lexer = 0;
1719 m_scriptCounter = 0;
1720 m_agent = 0;
1721 m_objectGeneration = 0;
1722 m_class_prev_id = QScriptClassInfo::CustomType;
1723 m_next_object_id = 0;
1724 m_gc_depth = -1;
1725
1726 objectConstructor = 0;
1727 numberConstructor = 0;
1728 booleanConstructor = 0;
1729 stringConstructor = 0;
1730 dateConstructor = 0;
1731 functionConstructor = 0;
1732 arrayConstructor = 0;
1733 regexpConstructor = 0;
1734 errorConstructor = 0;
1735 enumerationConstructor = 0;
1736 variantConstructor = 0;
1737 qobjectConstructor = 0;
1738 qmetaObjectConstructor = 0;
1739
1740 m_processEventsInterval = -1;
1741 m_nextProcessEvents = 0;
1742 m_processEventIncr = 0;
1743
1744 m_stringRepository.reserve(DefaultHashSize);
1745 m_string_hash_size = DefaultHashSize;
1746 m_string_hash_base = new QScriptNameIdImpl* [m_string_hash_size];
1747 memset(m_string_hash_base, 0, sizeof(QScriptNameIdImpl*) * m_string_hash_size);
1748
1749 tempStackBegin = 0;
1750}
1751
1752void QScriptEnginePrivate::init()
1753{
1754 qMetaTypeId<QScriptValue>();
1755 qMetaTypeId<QList<int> >();
1756#ifndef QT_NO_QOBJECT
1757 qMetaTypeId<QObjectList>();
1758#endif
1759
1760 m_class_prev_id = QScriptClassInfo::CustomType;
1761 m_class_object = registerClass(QLatin1String("Object"), QScriptClassInfo::ObjectType);
1762 m_class_function = registerClass(QLatin1String("Function"), QScriptClassInfo::FunctionType);
1763 m_class_activation = registerClass(QLatin1String("activation"), QScriptClassInfo::ActivationType);
1764
1765 m_class_arguments = registerClass(QLatin1String("arguments"), QScript::ObjectType);
1766 m_class_arguments->setData(new QScript::ArgumentsClassData());
1767
1768 m_class_with = registerClass(QLatin1String("__qscript_internal_with"), QScript::ObjectType);
1769
1770 // public name ids
1771 m_id_table.id_constructor = nameId(QLatin1String("constructor"), true);
1772 m_id_table.id_false = nameId(QLatin1String("false"), true);
1773 m_id_table.id_null = nameId(QLatin1String("null"), true);
1774 m_id_table.id_object = nameId(QLatin1String("object"), true);
1775 m_id_table.id_pointer = nameId(QLatin1String("pointer"), true);
1776 m_id_table.id_prototype = nameId(QLatin1String("prototype"), true);
1777 m_id_table.id_arguments = nameId(QLatin1String("arguments"), true);
1778 m_id_table.id_this = nameId(QLatin1String("this"), true);
1779 m_id_table.id_toString = nameId(QLatin1String("toString"), true);
1780 m_id_table.id_true = nameId(QLatin1String("true"), true);
1781 m_id_table.id_undefined = nameId(QLatin1String("undefined"), true);
1782 m_id_table.id_valueOf = nameId(QLatin1String("valueOf"), true);
1783 m_id_table.id_length = nameId(QLatin1String("length"), true);
1784 m_id_table.id_callee = nameId(QLatin1String("callee"), true);
1785 m_id_table.id___proto__ = nameId(QLatin1String("__proto__"), true);
1786 m_id_table.id___qt_sender__ = nameId(QLatin1String("__qt_sender__"), true);
1787
1788 const int TEMP_STACK_SIZE = 10 * 1024;
1789 tempStackBegin = new QScriptValueImpl[TEMP_STACK_SIZE];
1790 tempStackEnd = tempStackBegin + TEMP_STACK_SIZE;
1791 tempStackBegin[0] = m_undefinedValue;
1792
1793 objectAllocator.blockGC(true);
1794
1795 QScript::Ecma::Global::construct(&m_globalObject, this);
1796
1797 // create the prototypes first...
1798 objectConstructor = new QScript::Ecma::Object(this, m_class_object);
1799 functionConstructor = new QScript::Ecma::Function(this, m_class_function);
1800 // ... then we can initialize
1801 functionConstructor->initialize();
1802 objectConstructor->initialize();
1803
1804 numberConstructor = new QScript::Ecma::Number(this);
1805 booleanConstructor = new QScript::Ecma::Boolean(this);
1806 stringConstructor = new QScript::Ecma::String(this);
1807 dateConstructor = new QScript::Ecma::Date(this);
1808 arrayConstructor = new QScript::Ecma::Array(this);
1809 regexpConstructor = new QScript::Ecma::RegExp(this);
1810 errorConstructor = new QScript::Ecma::Error(this);
1811
1812 QScript::Ecma::Global::initialize(&m_globalObject, this);
1813
1814 const QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration;
1815
1816 m_globalObject.setProperty(QLatin1String("Object"),
1817 objectConstructor->ctor, flags);
1818 m_globalObject.setProperty(QLatin1String("Function"),
1819 functionConstructor->ctor, flags);
1820 m_globalObject.setProperty(QLatin1String("Number"),
1821 numberConstructor->ctor, flags);
1822 m_globalObject.setProperty(QLatin1String("Boolean"),
1823 booleanConstructor->ctor, flags);
1824 m_globalObject.setProperty(QLatin1String("String"),
1825 stringConstructor->ctor, flags);
1826 m_globalObject.setProperty(QLatin1String("Date"),
1827 dateConstructor->ctor, flags);
1828 m_globalObject.setProperty(QLatin1String("Array"),
1829 arrayConstructor->ctor, flags);
1830 m_globalObject.setProperty(QLatin1String("RegExp"),
1831 regexpConstructor->ctor, flags);
1832 m_globalObject.setProperty(QLatin1String("Error"),
1833 errorConstructor->ctor, flags);
1834
1835 m_globalObject.setProperty(QLatin1String("EvalError"),
1836 errorConstructor->evalErrorCtor, flags);
1837 m_globalObject.setProperty(QLatin1String("RangeError"),
1838 errorConstructor->rangeErrorCtor, flags);
1839 m_globalObject.setProperty(QLatin1String("ReferenceError"),
1840 errorConstructor->referenceErrorCtor, flags);
1841 m_globalObject.setProperty(QLatin1String("SyntaxError"),
1842 errorConstructor->syntaxErrorCtor, flags);
1843 m_globalObject.setProperty(QLatin1String("TypeError"),
1844 errorConstructor->typeErrorCtor, flags);
1845 m_globalObject.setProperty(QLatin1String("URIError"),
1846 errorConstructor->uriErrorCtor, flags);
1847
1848 QScriptValueImpl tmp; // ### fixme
1849 m_evalFunction = new QScript::EvalFunction(this);
1850 functionConstructor->newFunction(&tmp, m_evalFunction);
1851 m_globalObject.setProperty(QLatin1String("eval"), tmp, flags);
1852
1853 QScriptValueImpl mathObject;
1854 QScript::Ecma::Math::construct(&mathObject, this);
1855 m_globalObject.setProperty(QLatin1String("Math"), mathObject, flags);
1856
1857 enumerationConstructor = new QScript::Ext::Enumeration(this);
1858
1859 variantConstructor = new QScript::Ext::Variant(this);
1860
1861#ifndef QT_NO_QOBJECT
1862 qobjectConstructor = new QScript::ExtQObject(this);
1863 qmetaObjectConstructor = new QScript::ExtQMetaObject(this);
1864#endif
1865
1866 objectAllocator.blockGC(false);
1867
1868 QScriptContextPrivate *context_p = pushContext();
1869 context_p->setActivationObject(m_globalObject);
1870 context_p->setThisObject(m_globalObject);
1871}
1872
1873#if !defined(QT_NO_QOBJECT) && !defined(QT_NO_LIBRARY)
1874static QScriptValueImpl __setupPackage__(QScriptContextPrivate *ctx,
1875 QScriptEnginePrivate *eng,
1876 QScriptClassInfo *)
1877{
1878 QString path = ctx->argument(0).toString();
1879 QStringList components = path.split(QLatin1Char('.'));
1880 QScriptValueImpl o = eng->globalObject();
1881 for (int i = 0; i < components.count(); ++i) {
1882 QString name = components.at(i);
1883 QScriptValueImpl oo = o.property(name);
1884 if (!oo.isValid()) {
1885 oo = eng->newObject();
1886 o.setProperty(name, oo);
1887 }
1888 o = oo;
1889 }
1890 return o;
1891}
1892#endif
1893
1894QScriptValueImpl QScriptEnginePrivate::importExtension(const QString &extension)
1895{
1896#if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
1897 Q_UNUSED(extension);
1898#else
1899 Q_Q(QScriptEngine);
1900 if (m_importedExtensions.contains(extension))
1901 return undefinedValue(); // already imported
1902
1903 QScriptContextPrivate *context = currentContext();
1904 QCoreApplication *app = QCoreApplication::instance();
1905 if (!app)
1906 return context->throwError(QLatin1String("No application object"));
1907
1908 QObjectList staticPlugins = QPluginLoader::staticInstances();
1909 QStringList libraryPaths = app->libraryPaths();
1910 QString dot = QLatin1String(".");
1911 QStringList pathComponents = extension.split(dot);
1912 QString initDotJs = QLatin1String("__init__.js");
1913
1914 QString ext;
1915 for (int i = 0; i < pathComponents.count(); ++i) {
1916 if (!ext.isEmpty())
1917 ext.append(dot);
1918 ext.append(pathComponents.at(i));
1919 if (m_importedExtensions.contains(ext))
1920 continue; // already imported
1921
1922 if (m_extensionsBeingImported.contains(ext)) {
1923 return context->throwError(QString::fromLatin1("recursive import of %0")
1924 .arg(extension));
1925 }
1926 m_extensionsBeingImported.insert(ext);
1927
1928 QScriptExtensionInterface *iface = 0;
1929 QString initjsContents;
1930 QString initjsFileName;
1931
1932 // look for the extension in static plugins
1933 for (int j = 0; j < staticPlugins.size(); ++j) {
1934 iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(j));
1935 if (!iface)
1936 continue;
1937 if (iface->keys().contains(ext))
1938 break; // use this one
1939 else
1940 iface = 0; // keep looking
1941 }
1942
1943 {
1944 // look for __init__.js resource
1945 QString path = QString::fromLatin1(":/qtscriptextension");
1946 for (int j = 0; j <= i; ++j) {
1947 path.append(QLatin1Char('/'));
1948 path.append(pathComponents.at(j));
1949 }
1950 path.append(QLatin1Char('/'));
1951 path.append(initDotJs);
1952 QFile file(path);
1953 if (file.open(QIODevice::ReadOnly)) {
1954 QTextStream ts(&file);
1955 initjsContents = ts.readAll();
1956 initjsFileName = path;
1957 file.close();
1958 }
1959 }
1960
1961 if (!iface && initjsContents.isEmpty()) {
1962 // look for the extension in library paths
1963 for (int j = 0; j < libraryPaths.count(); ++j) {
1964 QString libPath = libraryPaths.at(j) + QDir::separator() + QLatin1String("script");
1965 QDir dir(libPath);
1966 if (!dir.exists(dot))
1967 continue;
1968
1969 // look for C++ plugin
1970 QFileInfoList files = dir.entryInfoList(QDir::Files);
1971 for (int k = 0; k < files.count(); ++k) {
1972 QFileInfo entry = files.at(k);
1973 QString filePath = entry.canonicalFilePath();
1974 QPluginLoader loader(filePath);
1975 iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
1976 if (iface) {
1977 if (iface->keys().contains(ext))
1978 break; // use this one
1979 else
1980 iface = 0; // keep looking
1981 }
1982 }
1983
1984 // look for __init__.js in the corresponding dir
1985 QDir dirdir(libPath);
1986 bool dirExists = dirdir.exists();
1987 for (int k = 0; dirExists && (k <= i); ++k)
1988 dirExists = dirdir.cd(pathComponents.at(k));
1989 if (dirExists && dirdir.exists(initDotJs)) {
1990 QFile file(dirdir.canonicalPath()
1991 + QDir::separator() + initDotJs);
1992 if (file.open(QIODevice::ReadOnly)) {
1993 QTextStream ts(&file);
1994 initjsContents = ts.readAll();
1995 initjsFileName = file.fileName();
1996 file.close();
1997 }
1998 }
1999
2000 if (iface || !initjsContents.isEmpty())
2001 break;
2002 }
2003 }
2004
2005 if (!iface && initjsContents.isEmpty()) {
2006 m_extensionsBeingImported.remove(ext);
2007 return context->throwError(
2008 QString::fromLatin1("Unable to import %0: no such extension")
2009 .arg(extension));
2010 }
2011
2012 // initialize the extension in a new context
2013 QScriptContextPrivate *ctx_p = pushContext();
2014 ctx_p->setThisObject(globalObject());
2015 newActivation(&ctx_p->m_activation);
2016 QScriptObject *activation_data = ctx_p->m_activation.m_object_value;
2017 activation_data->m_scope = globalObject();
2018
2019 activation_data->m_members.resize(4);
2020 activation_data->m_values.resize(4);
2021 activation_data->m_members[0].object(
2022 nameId(QLatin1String("__extension__")), 0,
2023 QScriptValue::ReadOnly | QScriptValue::Undeletable);
2024 activation_data->m_values[0] = QScriptValueImpl(this, ext);
2025 activation_data->m_members[1].object(
2026 nameId(QLatin1String("__setupPackage__")), 1, 0);
2027 activation_data->m_values[1] = createFunction(__setupPackage__, 0, 0);
2028 activation_data->m_members[2].object(
2029 nameId(QLatin1String("__all__")), 2, 0);
2030 activation_data->m_values[2] = undefinedValue();
2031 activation_data->m_members[3].object(
2032 nameId(QLatin1String("__postInit__")), 3, 0);
2033 activation_data->m_values[3] = undefinedValue();
2034
2035 // the script is evaluated first
2036 if (!initjsContents.isEmpty()) {
2037 evaluate(ctx_p, initjsContents, /*lineNumber=*/1, initjsFileName);
2038 if (hasUncaughtException()) {
2039 QScriptValueImpl r = ctx_p->returnValue();
2040 popContext();
2041 m_extensionsBeingImported.remove(ext);
2042 return r;
2043 }
2044 }
2045
2046 // next, the C++ plugin is called
2047 if (iface) {
2048 iface->initialize(ext, q);
2049 if (hasUncaughtException()) {
2050 QScriptValueImpl r = ctx_p->returnValue();
2051 popContext();
2052 m_extensionsBeingImported.remove(ext);
2053 return r;
2054 }
2055 }
2056
2057 // if the __postInit__ function has been set, we call it
2058 QScriptValueImpl postInit = ctx_p->m_activation.property(QLatin1String("__postInit__"));
2059 if (postInit.isFunction()) {
2060 postInit.call(globalObject());
2061 if (hasUncaughtException()) {
2062 QScriptValueImpl r = ctx_p->returnValue();
2063 popContext();
2064 m_extensionsBeingImported.remove(ext);
2065 return r;
2066 }
2067 }
2068
2069 popContext();
2070
2071 m_importedExtensions.insert(ext);
2072 m_extensionsBeingImported.remove(ext);
2073 } // for (i)
2074#endif // QT_NO_QOBJECT
2075 return undefinedValue();
2076}
2077
2078QStringList QScriptEnginePrivate::availableExtensions() const
2079{
2080#if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
2081 return QStringList();
2082#else
2083 QCoreApplication *app = QCoreApplication::instance();
2084 if (!app)
2085 return QStringList();
2086
2087 QSet<QString> result;
2088
2089 QObjectList staticPlugins = QPluginLoader::staticInstances();
2090 for (int i = 0; i < staticPlugins.size(); ++i) {
2091 QScriptExtensionInterface *iface;
2092 iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(i));
2093 if (iface) {
2094 QStringList keys = iface->keys();
2095 for (int j = 0; j < keys.count(); ++j)
2096 result << keys.at(j);
2097 }
2098 }
2099
2100 QStringList libraryPaths = app->libraryPaths();
2101 for (int i = 0; i < libraryPaths.count(); ++i) {
2102 QString libPath = libraryPaths.at(i) + QDir::separator() + QLatin1String("script");
2103 QDir dir(libPath);
2104 if (!dir.exists())
2105 continue;
2106
2107 // look for C++ plugins
2108 QFileInfoList files = dir.entryInfoList(QDir::Files);
2109 for (int j = 0; j < files.count(); ++j) {
2110 QFileInfo entry = files.at(j);
2111 QString filePath = entry.canonicalFilePath();
2112 QPluginLoader loader(filePath);
2113 QScriptExtensionInterface *iface;
2114 iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
2115 if (iface) {
2116 QStringList keys = iface->keys();
2117 for (int k = 0; k < keys.count(); ++k)
2118 result << keys.at(k);
2119 }
2120 }
2121
2122 // look for scripts
2123 QString initDotJs = QLatin1String("__init__.js");
2124 QList<QFileInfo> stack;
2125 stack << dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
2126 while (!stack.isEmpty()) {
2127 QFileInfo entry = stack.takeLast();
2128 QDir dd(entry.canonicalFilePath());
2129 if (dd.exists(initDotJs)) {
2130 QString rpath = dir.relativeFilePath(dd.canonicalPath());
2131 QStringList components = rpath.split(QLatin1Char('/'));
2132 result << components.join(QLatin1String("."));
2133 stack << dd.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
2134 }
2135 }
2136 }
2137
2138 QStringList lst = result.toList();
2139 qSort(lst);
2140 return lst;
2141#endif
2142}
2143
2144QStringList QScriptEnginePrivate::importedExtensions() const
2145{
2146 QStringList lst = m_importedExtensions.toList();
2147 qSort(lst);
2148 return lst;
2149}
2150
2151void QScriptEnginePrivate::gc()
2152{
2153 if (!objectAllocator.blocked()) {
2154 // do the GC now
2155 maybeGC_helper(/*do_string_gc=*/true);
2156 } else {
2157 // GC will be performed the next time maybeGC()
2158 // is called and the allocator is not blocked
2159 objectAllocator.requestGC();
2160 }
2161}
2162
2163QStringList QScriptEnginePrivate::uncaughtExceptionBacktrace() const
2164{
2165 QScriptValueImpl value = uncaughtException();
2166 if (!value.isError())
2167 return m_exceptionBacktrace;
2168 return QScript::Ecma::Error::backtrace(value);
2169}
2170
2171void QScriptEnginePrivate::clearExceptions()
2172{
2173 m_exceptionBacktrace = QStringList();
2174 QScriptContextPrivate *ctx_p = currentContext();
2175 while (ctx_p) {
2176 ctx_p->m_state = QScriptContext::NormalState;
2177 ctx_p = ctx_p->parentContext();
2178 }
2179}
2180
2181#ifndef QT_NO_QOBJECT
2182void QScriptEnginePrivate::emitSignalHandlerException()
2183{
2184 Q_Q(QScriptEngine);
2185 emit q->signalHandlerException(toPublic(uncaughtException()));
2186}
2187#endif
2188
2189void QScriptEnginePrivate::processEvents()
2190{
2191#ifndef QT_NO_QOBJECT
2192 Q_ASSERT(m_processEventTracker.isValid());
2193 int elapsed = m_processEventTracker.elapsed();
2194 if (m_nextProcessEvents < elapsed) {
2195 do {
2196 m_nextProcessEvents = m_nextProcessEvents + m_processEventsInterval;
2197 } while (m_nextProcessEvents < elapsed);
2198 QCoreApplication::processEvents();
2199 }
2200#endif
2201}
2202
2203void QScriptEnginePrivate::setupProcessEvents()
2204{
2205 if (m_processEventsInterval > 0) {
2206 m_nextProcessEvents = m_processEventsInterval;
2207 m_processEventIncr = 0;
2208 m_processEventTracker.restart();
2209 }
2210}
2211
2212void QScriptEnginePrivate::abortEvaluation(const QScriptValueImpl &result)
2213{
2214 m_abort = true;
2215 currentContext()->setReturnValue(result);
2216}
2217
2218#ifndef QT_NO_QOBJECT
2219
2220void QScriptEnginePrivate::newQObject(QScriptValueImpl *out, QObject *object,
2221 QScriptEngine::ValueOwnership ownership,
2222 const QScriptEngine::QObjectWrapOptions &options,
2223 bool setDefaultPrototype)
2224{
2225 if (!object) {
2226 *out = m_nullValue;
2227 return;
2228 }
2229 Q_ASSERT(qobjectConstructor != 0);
2230 QScriptQObjectData *data = qobjectData(object);
2231 bool preferExisting = (options & QScriptEngine::PreferExistingWrapperObject) != 0;
2232 QScriptEngine::QObjectWrapOptions opt = options & ~QScriptEngine::PreferExistingWrapperObject;
2233 QScriptValueImpl existingWrapper;
2234 bool hasExisting = data->findWrapper(ownership, opt, &existingWrapper);
2235 if (preferExisting) {
2236 if (hasExisting) {
2237 *out = existingWrapper;
2238 } else {
2239 qobjectConstructor->newQObject(out, object, ownership, opt);
2240 data->registerWrapper(*out, ownership, opt);
2241 }
2242 } else {
2243 qobjectConstructor->newQObject(out, object, ownership, opt);
2244 if (!hasExisting)
2245 data->registerWrapper(*out, ownership, opt);
2246 }
2247
2248 if (setDefaultPrototype) {
2249 const QMetaObject *meta = object->metaObject();
2250 while (meta) {
2251 QByteArray typeString = meta->className();
2252 typeString.append('*');
2253 int typeId = QMetaType::type(typeString);
2254 if (typeId != 0) {
2255 QScriptValueImpl proto = defaultPrototype(typeId);
2256 if (proto.isValid()) {
2257 out->setPrototype(proto);
2258 break;
2259 }
2260 }
2261 meta = meta->superClass();
2262 }
2263 }
2264}
2265
2266QScriptQObjectData *QScriptEnginePrivate::qobjectData(QObject *object)
2267{
2268 QHash<QObject*, QScriptQObjectData*>::const_iterator it;
2269 it = m_qobjectData.constFind(object);
2270 if (it != m_qobjectData.constEnd())
2271 return it.value();
2272
2273 QScriptQObjectData *data = new QScriptQObjectData();
2274 m_qobjectData.insert(object, data);
2275 QObject::connect(object, SIGNAL(destroyed(QObject*)),
2276 q_func(), SLOT(_q_objectDestroyed(QObject *)));
2277 return data;
2278}
2279
2280void QScriptEnginePrivate::_q_objectDestroyed(QObject *object)
2281{
2282 QHash<QObject*, QScriptQObjectData*>::iterator it;
2283 it = m_qobjectData.find(object);
2284 Q_ASSERT(it != m_qobjectData.end());
2285 QScriptQObjectData *data = it.value();
2286 m_qobjectData.erase(it);
2287 delete data;
2288}
2289
2290void QScriptEnginePrivate::disposeQObject(QObject *object)
2291{
2292 if (isCollecting()) {
2293 // wait until we're done with GC before deleting it
2294 int index = m_qobjectsToBeDeleted.indexOf(object);
2295 if (index == -1)
2296 m_qobjectsToBeDeleted.append(object);
2297 } else {
2298 delete object;
2299 }
2300}
2301
2302void QScriptEnginePrivate::deletePendingQObjects()
2303{
2304 while (!m_qobjectsToBeDeleted.isEmpty())
2305 delete m_qobjectsToBeDeleted.takeFirst();
2306}
2307
2308bool QScriptEnginePrivate::scriptConnect(QObject *sender, const char *signal,
2309 const QScriptValueImpl &receiver,
2310 const QScriptValueImpl &function)
2311{
2312 Q_ASSERT(sender);
2313 Q_ASSERT(signal);
2314 const QMetaObject *meta = sender->metaObject();
2315 int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
2316 if (index == -1)
2317 return false;
2318 return scriptConnect(sender, index, receiver, function);
2319}
2320
2321bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, const char *signal,
2322 const QScriptValueImpl &receiver,
2323 const QScriptValueImpl &function)
2324{
2325 Q_ASSERT(sender);
2326 Q_ASSERT(signal);
2327 const QMetaObject *meta = sender->metaObject();
2328 int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
2329 if (index == -1)
2330 return false;
2331 return scriptDisconnect(sender, index, receiver, function);
2332}
2333
2334bool QScriptEnginePrivate::scriptConnect(QObject *sender, int signalIndex,
2335 const QScriptValueImpl &receiver,
2336 const QScriptValueImpl &function,
2337 const QScriptValueImpl &senderWrapper)
2338{
2339 QScriptQObjectData *data = qobjectData(sender);
2340 return data->addSignalHandler(sender, signalIndex, receiver, function, senderWrapper);
2341}
2342
2343bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, int signalIndex,
2344 const QScriptValueImpl &receiver,
2345 const QScriptValueImpl &function)
2346{
2347 QScriptQObjectData *data = qobjectData(sender);
2348 if (!data)
2349 return false;
2350 return data->removeSignalHandler(sender, signalIndex, receiver, function);
2351}
2352
2353bool QScriptEnginePrivate::scriptConnect(const QScriptValueImpl &signal,
2354 const QScriptValueImpl &receiver,
2355 const QScriptValueImpl &function)
2356{
2357 QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(signal.toFunction());
2358 int index = fun->mostGeneralMethod();
2359 return scriptConnect(fun->qobject(), index, receiver, function, fun->object());
2360}
2361
2362bool QScriptEnginePrivate::scriptDisconnect(const QScriptValueImpl &signal,
2363 const QScriptValueImpl &receiver,
2364 const QScriptValueImpl &function)
2365{
2366 QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(signal.toFunction());
2367 int index = fun->mostGeneralMethod();
2368 return scriptDisconnect(fun->qobject(), index, receiver, function);
2369}
2370
2371bool QScriptEnginePrivate::convertToNativeQObject(const QScriptValueImpl &value,
2372 const QByteArray &targetType,
2373 void **result)
2374{
2375 if (!targetType.endsWith('*'))
2376 return false;
2377 if (QObject *qobject = value.toQObject()) {
2378 int start = targetType.startsWith("const ") ? 6 : 0;
2379 QByteArray className = targetType.mid(start, targetType.size()-start-1);
2380 if (void *instance = qobject->qt_metacast(className)) {
2381 *result = instance;
2382 return true;
2383 }
2384 }
2385 return false;
2386}
2387
2388#endif // QT_NO_QOBJECT
2389
2390void QScriptEnginePrivate::setAgent(QScriptEngineAgent *agent)
2391{
2392 Q_Q(QScriptEngine);
2393 if (agent && (agent->engine() != q)) {
2394 qWarning("QScriptEngine::setAgent(): "
2395 "cannot set agent belonging to different engine");
2396 return;
2397 }
2398 if (agent) {
2399 int index = m_agents.indexOf(agent);
2400 if (index == -1)
2401 m_agents.append(agent);
2402 }
2403 m_agent = agent;
2404}
2405
2406QScriptEngineAgent *QScriptEnginePrivate::agent() const
2407{
2408 return m_agent;
2409}
2410
2411void QScriptEnginePrivate::agentDeleted(QScriptEngineAgent *agent)
2412{
2413 m_agents.removeOne(agent);
2414 if (m_agent == agent)
2415 m_agent = 0;
2416}
2417
2418#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
2419qint64 QScriptEnginePrivate::nextScriptId()
2420{
2421 // ### reuse IDs by using a pool
2422 return m_scriptCounter++;
2423}
2424
2425void QScriptEnginePrivate::notifyScriptLoad_helper(qint64 id, const QString &program,
2426 const QString &fileName, int lineNumber)
2427{
2428 m_agent->scriptLoad(id, program, fileName, lineNumber);
2429}
2430
2431void QScriptEnginePrivate::notifyScriptUnload_helper(qint64 id)
2432{
2433 m_agent->scriptUnload(id);
2434}
2435
2436void QScriptEnginePrivate::notifyPositionChange_helper(QScriptContextPrivate *ctx)
2437{
2438 m_agent->positionChange(ctx->scriptId(), ctx->currentLine, ctx->currentColumn);
2439}
2440
2441void QScriptEnginePrivate::notifyContextPush_helper()
2442{
2443 m_agent->contextPush();
2444}
2445
2446void QScriptEnginePrivate::notifyContextPop_helper()
2447{
2448 m_agent->contextPop();
2449}
2450
2451void QScriptEnginePrivate::notifyFunctionEntry_helper(QScriptContextPrivate *ctx)
2452{
2453 m_agent->functionEntry(ctx->scriptId());
2454}
2455
2456void QScriptEnginePrivate::notifyFunctionExit_helper(QScriptContextPrivate *ctx)
2457{
2458 m_agent->functionExit(ctx->scriptId(), toPublic(ctx->returnValue()));
2459}
2460
2461void QScriptEnginePrivate::notifyException_helper(QScriptContextPrivate *ctx)
2462{
2463 bool hasHandler = (ctx->exceptionHandlerContext() != 0);
2464 m_agent->exceptionThrow(ctx->scriptId(), toPublic(ctx->returnValue()), hasHandler);
2465}
2466
2467void QScriptEnginePrivate::notifyExceptionCatch_helper(QScriptContextPrivate *ctx)
2468{
2469 m_agent->exceptionCatch(ctx->scriptId(), toPublic(ctx->returnValue()));
2470}
2471
2472void QScriptEnginePrivate::notifyDebugger(QScriptContextPrivate *ctx)
2473{
2474 if (m_agent && m_agent->supportsExtension(QScriptEngineAgent::DebuggerInvocationRequest)) {
2475 QVariantList args;
2476 args.append(ctx->scriptId());
2477 args.append(ctx->currentLine);
2478 args.append(ctx->currentColumn);
2479 QVariant ret = m_agent->extension(QScriptEngineAgent::DebuggerInvocationRequest, args);
2480 QScriptValueImpl val = valueFromVariant(ret);
2481 if (val.isValid())
2482 ctx->m_result = val;
2483 }
2484}
2485
2486#endif // Q_SCRIPT_NO_EVENT_NOTIFY
2487
2488QScriptString QScriptEnginePrivate::internedString(const QString &str)
2489{
2490 return internedString(nameId(str, /*persistent=*/false));
2491}
2492
2493QScriptString QScriptEnginePrivate::internedString(QScriptNameIdImpl *nid)
2494{
2495 if (!nid)
2496 return QScriptString();
2497 QScriptStringPrivate *d = m_internedStrings.value(nid);
2498 if (!d) {
2499 d = m_internedStringRepository.get();
2500 d->nameId = nid;
2501 d->engine = this;
2502 m_internedStrings.insert(d->nameId, d);
2503 }
2504 QScriptString result;
2505 QScriptStringPrivate::init(result, d);
2506 return result;
2507}
2508
2509void QScriptEnginePrivate::uninternString(QScriptStringPrivate *d)
2510{
2511 Q_ASSERT(d->nameId);
2512 QHash<QScriptNameIdImpl*, QScriptStringPrivate*>::iterator it;
2513 it = m_internedStrings.find(d->nameId);
2514 Q_ASSERT(it != m_internedStrings.end());
2515 m_internedStrings.erase(it);
2516 m_internedStringRepository.release(d);
2517}
2518
2519QScriptValueImpl QScriptEnginePrivate::toImpl_helper(const QScriptValue &value)
2520{
2521 QScriptValuePrivate *p = QScriptValuePrivate::get(value);
2522 Q_ASSERT(p != 0);
2523 Q_ASSERT(p->value.type() == QScript::LazyStringType);
2524 QString str = *p->value.m_lazy_string_value;
2525 if (!p->ref.deref())
2526 delete p;
2527 QScriptValueImpl v;
2528 newString(&v, str);
2529 p = registerValue(v);
2530 QScriptValuePrivate::init(const_cast<QScriptValue&>(value), p);
2531 return v;
2532}
2533
2534QScriptValueImpl QScriptEnginePrivate::newObject(QScriptClass *scriptClass,
2535 const QScriptValueImpl &data)
2536{
2537 if (!scriptClass)
2538 return QScriptValueImpl();
2539 QScriptValueImpl v;
2540 QScriptValueImpl proto = toImpl(scriptClass->prototype());
2541 if (!proto.isObject())
2542 proto = objectConstructor->publicPrototype;
2543 newObject(&v, proto);
2544 QScriptClassPrivate *cls_p = QScriptClassPrivate::get(scriptClass);
2545 QScriptClassInfo *info = cls_p->classInfo();
2546 v.setClassInfo(info);
2547 if (info->type() & QScriptClassInfo::FunctionBased) {
2548 QScriptFunction *fun = cls_p->newFunction();
2549 v.setObjectData(fun);
2550 }
2551 v.setInternalValue(data);
2552 return v;
2553}
2554
2555int QScriptEnginePrivate::registerCustomClassType()
2556{
2557 return ++m_class_prev_id;
2558}
2559
2560QScriptValueImpl QScriptEnginePrivate::objectById(qint64 id) const
2561{
2562 QScript::GCAlloc<QScriptObject>::const_iterator it;
2563 for (it = objectAllocator.constBegin(); it != objectAllocator.constEnd(); ++it) {
2564 const QScriptObject *obj = it.data();
2565 if (obj->m_id == id) {
2566 QScriptValueImpl ret;
2567 ret.m_type = QScript::ObjectType;
2568 ret.m_object_value = const_cast<QScriptObject*>(obj);
2569 return ret;
2570 }
2571 }
2572 return QScriptValueImpl();
2573}
2574
2575namespace QScript {
2576
2577static QScriptValueImpl qsTranslate(QScriptContextPrivate *ctx, QScriptEnginePrivate *eng, QScriptClassInfo *)
2578{
2579 if (ctx->argumentCount() < 2)
2580 return ctx->throwError(QString::fromLatin1("qsTranslate() requires at least two arguments"));
2581 if (!ctx->argument(0).isString())
2582 return ctx->throwError(QString::fromLatin1("qsTranslate(): first argument (context) must be a string"));
2583 if (!ctx->argument(1).isString())
2584 return ctx->throwError(QString::fromLatin1("qsTranslate(): second argument (text) must be a string"));
2585 if ((ctx->argumentCount() > 2) && !ctx->argument(2).isString())
2586 return ctx->throwError(QString::fromLatin1("qsTranslate(): third argument (comment) must be a string"));
2587 if ((ctx->argumentCount() > 3) && !ctx->argument(3).isString())
2588 return ctx->throwError(QString::fromLatin1("qsTranslate(): fourth argument (encoding) must be a string"));
2589 if ((ctx->argumentCount() > 4) && !ctx->argument(4).isNumber())
2590 return ctx->throwError(QString::fromLatin1("qsTranslate(): fifth argument (n) must be a number"));
2591#ifndef QT_NO_QOBJECT
2592 QString context = ctx->argument(0).toString();
2593#endif
2594 QString text = ctx->argument(1).toString();
2595#ifndef QT_NO_QOBJECT
2596 QString comment;
2597 if (ctx->argumentCount() > 2)
2598 comment = ctx->argument(2).toString();
2599 QCoreApplication::Encoding encoding = QCoreApplication::CodecForTr;
2600 if (ctx->argumentCount() > 3) {
2601 QString encStr = ctx->argument(3).toString();
2602 if (encStr == QLatin1String("CodecForTr"))
2603 encoding = QCoreApplication::CodecForTr;
2604 else if (encStr == QLatin1String("UnicodeUTF8"))
2605 encoding = QCoreApplication::UnicodeUTF8;
2606 else
2607 return ctx->throwError(QString::fromLatin1("qsTranslate(): invalid encoding '%s'").arg(encStr));
2608 }
2609 int n = -1;
2610 if (ctx->argumentCount() > 4)
2611 n = ctx->argument(4).toInt32();
2612#endif
2613 QString result;
2614#ifndef QT_NO_QOBJECT
2615 result = QCoreApplication::translate(context.toLatin1().constData(),
2616 text.toLatin1().constData(),
2617 comment.toLatin1().constData(),
2618 encoding, n);
2619#else
2620 result = text;
2621#endif
2622 return QScriptValueImpl(eng, result);
2623}
2624
2625static QScriptValueImpl qTranslateNoOp(QScriptContextPrivate *ctx, QScriptEnginePrivate *, QScriptClassInfo *)
2626{
2627 return ctx->argument(1);
2628}
2629
2630static QScriptValueImpl qsTr(QScriptContextPrivate *ctx, QScriptEnginePrivate *eng, QScriptClassInfo *)
2631{
2632 if (ctx->argumentCount() < 1)
2633 return ctx->throwError(QString::fromLatin1("qsTr() requires at least one argument"));
2634 if (!ctx->argument(0).isString())
2635 return ctx->throwError(QString::fromLatin1("qsTr(): first argument (text) must be a string"));
2636 if ((ctx->argumentCount() > 1) && !ctx->argument(1).isString())
2637 return ctx->throwError(QString::fromLatin1("qsTr(): second argument (comment) must be a string"));
2638 if ((ctx->argumentCount() > 2) && !ctx->argument(2).isNumber())
2639 return ctx->throwError(QString::fromLatin1("qsTranslate(): third argument (n) must be a number"));
2640#ifndef QT_NO_QOBJECT
2641 QString context;
2642 if (ctx->parentContext())
2643 context = QFileInfo(ctx->parentContext()->fileName()).baseName();
2644#endif
2645 QString text = ctx->argument(0).toString();
2646#ifndef QT_NO_QOBJECT
2647 QString comment;
2648 if (ctx->argumentCount() > 1)
2649 comment = ctx->argument(1).toString();
2650 int n = -1;
2651 if (ctx->argumentCount() > 2)
2652 n = ctx->argument(2).toInt32();
2653#endif
2654 QString result;
2655#ifndef QT_NO_QOBJECT
2656 result = QCoreApplication::translate(context.toLatin1().constData(),
2657 text.toLatin1().constData(),
2658 comment.toLatin1().constData(),
2659 QCoreApplication::CodecForTr, n);
2660#else
2661 result = text;
2662#endif
2663 return QScriptValueImpl(eng, result);
2664}
2665
2666static QScriptValueImpl qTrNoOp(QScriptContextPrivate *ctx, QScriptEnginePrivate *, QScriptClassInfo *)
2667{
2668 return ctx->argument(0);
2669}
2670
2671} // namespace QScript
2672
2673void QScriptEnginePrivate::installTranslatorFunctions(QScriptValueImpl &object)
2674{
2675 Q_ASSERT(object.isObject());
2676 const QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration;
2677 object.setProperty(QLatin1String("qsTranslate"),
2678 createFunction(QScript::qsTranslate, /*length=*/5, /*classInfo=*/0),
2679 flags);
2680 object.setProperty(QLatin1String("QT_TRANSLATE_NOOP"),
2681 createFunction(QScript::qTranslateNoOp, /*length=*/2, /*classInfo=*/0),
2682 flags);
2683 object.setProperty(QLatin1String("qsTr"),
2684 createFunction(QScript::qsTr, /*length=*/3, /*classInfo=*/0),
2685 flags);
2686 object.setProperty(QLatin1String("QT_TR_NOOP"),
2687 createFunction(QScript::qTrNoOp, /*length=*/1, /*classInfo=*/0),
2688 flags);
2689
2690 stringConstructor->addPrototypeFunction(QLatin1String("arg"), QScript::Ecma::String::method_ext_arg, 1);
2691}
2692
2693bool QScriptEnginePrivate::canEvaluate(const QString &program)
2694{
2695 QScript::SyntaxChecker checker;
2696 QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2697 return (result.state != QScript::SyntaxChecker::Intermediate);
2698}
2699
2700QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &program)
2701{
2702 QScript::SyntaxChecker checker;
2703 QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2704 QScriptSyntaxCheckResultPrivate *p = new QScriptSyntaxCheckResultPrivate();
2705 switch (result.state) {
2706 case QScript::SyntaxChecker::Error:
2707 p->state = QScriptSyntaxCheckResult::Error;
2708 break;
2709 case QScript::SyntaxChecker::Intermediate:
2710 p->state = QScriptSyntaxCheckResult::Intermediate;
2711 break;
2712 case QScript::SyntaxChecker::Valid:
2713 p->state = QScriptSyntaxCheckResult::Valid;
2714 break;
2715 }
2716 p->errorLineNumber = result.errorLineNumber;
2717 p->errorColumnNumber = result.errorColumnNumber;
2718 p->errorMessage = result.errorMessage;
2719 return QScriptSyntaxCheckResult(p);
2720}
2721
2722QT_END_NAMESPACE
2723
2724#endif // QT_NO_SCRIPT
Note: See TracBrowser for help on using the repository browser.