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 |
|
---|
81 | Q_DECLARE_METATYPE(QScriptValue)
|
---|
82 | #ifndef QT_NO_QOBJECT
|
---|
83 | Q_DECLARE_METATYPE(QObjectList)
|
---|
84 | #endif
|
---|
85 | Q_DECLARE_METATYPE(QList<int>)
|
---|
86 |
|
---|
87 | QT_BEGIN_NAMESPACE
|
---|
88 |
|
---|
89 | extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str);
|
---|
90 | extern double qstrtod(const char *s00, char const **se, bool *ok);
|
---|
91 |
|
---|
92 | namespace QScript {
|
---|
93 |
|
---|
94 | QString 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 |
|
---|
168 | static 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 |
|
---|
179 | qsreal 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 |
|
---|
232 | qsreal integerFromString(const QString &str, int radix)
|
---|
233 | {
|
---|
234 | QByteArray ba = str.trimmed().toUtf8();
|
---|
235 | return integerFromString(ba.constData(), ba.size(), radix);
|
---|
236 | }
|
---|
237 |
|
---|
238 | qsreal 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 |
|
---|
264 | NodePool::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 |
|
---|
272 | NodePool::~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 |
|
---|
282 | Code *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 |
|
---|
295 | class EvalFunction : public QScriptFunction
|
---|
296 | {
|
---|
297 | public:
|
---|
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 |
|
---|
402 | class ArgumentsClassData: public QScriptClassData
|
---|
403 | {
|
---|
404 |
|
---|
405 | public:
|
---|
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 |
|
---|
421 | class ArgumentsClassDataIterator: public QScriptClassDataIterator
|
---|
422 | {
|
---|
423 | public:
|
---|
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 |
|
---|
436 | private:
|
---|
437 | ArgumentsObjectData *m_data;
|
---|
438 | uint m_pos;
|
---|
439 | };
|
---|
440 |
|
---|
441 | bool 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 |
|
---|
460 | bool 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 |
|
---|
472 | bool 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 |
|
---|
482 | void ArgumentsClassData::mark(const QScriptValueImpl &object, int generation)
|
---|
483 | {
|
---|
484 | QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object);
|
---|
485 | data->activation.mark(generation);
|
---|
486 | }
|
---|
487 |
|
---|
488 | QScriptClassDataIterator *ArgumentsClassData::newIterator(const QScriptValueImpl &object)
|
---|
489 | {
|
---|
490 | QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object);
|
---|
491 | return new ArgumentsClassDataIterator(data);
|
---|
492 | }
|
---|
493 |
|
---|
494 | ArgumentsClassDataIterator::ArgumentsClassDataIterator(ArgumentsObjectData *data)
|
---|
495 | : m_data(data), m_pos(0)
|
---|
496 | {
|
---|
497 | }
|
---|
498 |
|
---|
499 | ArgumentsClassDataIterator::~ArgumentsClassDataIterator()
|
---|
500 | {
|
---|
501 | }
|
---|
502 |
|
---|
503 | bool ArgumentsClassDataIterator::hasNext() const
|
---|
504 | {
|
---|
505 | return m_pos < m_data->length;
|
---|
506 | }
|
---|
507 |
|
---|
508 | void 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 |
|
---|
518 | bool ArgumentsClassDataIterator::hasPrevious() const
|
---|
519 | {
|
---|
520 | return (m_pos != 0);
|
---|
521 | }
|
---|
522 |
|
---|
523 | void 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 |
|
---|
533 | void ArgumentsClassDataIterator::toFront()
|
---|
534 | {
|
---|
535 | m_pos = 0;
|
---|
536 | }
|
---|
537 |
|
---|
538 | void ArgumentsClassDataIterator::toBack()
|
---|
539 | {
|
---|
540 | m_pos = m_data->length;
|
---|
541 | }
|
---|
542 |
|
---|
543 | } // namespace QScript
|
---|
544 |
|
---|
545 | const qsreal QScriptEnginePrivate::D16 = 65536.0;
|
---|
546 | const qsreal QScriptEnginePrivate::D32 = 4294967296.0;
|
---|
547 |
|
---|
548 | QScriptEnginePrivate::~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 |
|
---|
595 | QScript::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 |
|
---|
602 | QScript::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 |
|
---|
622 | void 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 |
|
---|
713 | void 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 |
|
---|
765 | bool QScriptEnginePrivate::isCollecting() const
|
---|
766 | {
|
---|
767 | return (m_gc_depth != -1) || objectAllocator.sweeping();
|
---|
768 | }
|
---|
769 |
|
---|
770 | void 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 |
|
---|
927 | void 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 |
|
---|
934 | void 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 |
|
---|
941 | qsreal 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 |
|
---|
984 | bool 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 |
|
---|
1020 | QString 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 |
|
---|
1077 | QScriptValueImpl 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]]
|
---|
1111 | QScriptValueImpl 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 |
|
---|
1159 | void 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 |
|
---|
1179 | QScriptNameIdImpl *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 |
|
---|
1197 | QScriptValueImpl 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 |
|
---|
1266 | QScriptValueImpl 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 |
|
---|
1295 | QScriptValueImpl 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 |
|
---|
1303 | QStringList 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 |
|
---|
1312 | QScriptValueImpl 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 |
|
---|
1320 | QVariantList 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 |
|
---|
1329 | QScriptValueImpl 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 |
|
---|
1338 | QVariantMap 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 |
|
---|
1349 | QScriptValueImpl 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 |
|
---|
1475 | bool 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 |
|
---|
1665 | QScriptValuePrivate *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 |
|
---|
1695 | QScriptEnginePrivate::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 |
|
---|
1752 | void 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)
|
---|
1874 | static 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 |
|
---|
1894 | QScriptValueImpl 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 |
|
---|
2078 | QStringList 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 |
|
---|
2144 | QStringList QScriptEnginePrivate::importedExtensions() const
|
---|
2145 | {
|
---|
2146 | QStringList lst = m_importedExtensions.toList();
|
---|
2147 | qSort(lst);
|
---|
2148 | return lst;
|
---|
2149 | }
|
---|
2150 |
|
---|
2151 | void 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 |
|
---|
2163 | QStringList 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 |
|
---|
2171 | void 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
|
---|
2182 | void QScriptEnginePrivate::emitSignalHandlerException()
|
---|
2183 | {
|
---|
2184 | Q_Q(QScriptEngine);
|
---|
2185 | emit q->signalHandlerException(toPublic(uncaughtException()));
|
---|
2186 | }
|
---|
2187 | #endif
|
---|
2188 |
|
---|
2189 | void 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 |
|
---|
2203 | void QScriptEnginePrivate::setupProcessEvents()
|
---|
2204 | {
|
---|
2205 | if (m_processEventsInterval > 0) {
|
---|
2206 | m_nextProcessEvents = m_processEventsInterval;
|
---|
2207 | m_processEventIncr = 0;
|
---|
2208 | m_processEventTracker.restart();
|
---|
2209 | }
|
---|
2210 | }
|
---|
2211 |
|
---|
2212 | void QScriptEnginePrivate::abortEvaluation(const QScriptValueImpl &result)
|
---|
2213 | {
|
---|
2214 | m_abort = true;
|
---|
2215 | currentContext()->setReturnValue(result);
|
---|
2216 | }
|
---|
2217 |
|
---|
2218 | #ifndef QT_NO_QOBJECT
|
---|
2219 |
|
---|
2220 | void 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 |
|
---|
2266 | QScriptQObjectData *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 |
|
---|
2280 | void 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 |
|
---|
2290 | void 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 |
|
---|
2302 | void QScriptEnginePrivate::deletePendingQObjects()
|
---|
2303 | {
|
---|
2304 | while (!m_qobjectsToBeDeleted.isEmpty())
|
---|
2305 | delete m_qobjectsToBeDeleted.takeFirst();
|
---|
2306 | }
|
---|
2307 |
|
---|
2308 | bool 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 |
|
---|
2321 | bool 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 |
|
---|
2334 | bool 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 |
|
---|
2343 | bool 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 |
|
---|
2353 | bool 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 |
|
---|
2362 | bool 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 |
|
---|
2371 | bool 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 |
|
---|
2390 | void 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 |
|
---|
2406 | QScriptEngineAgent *QScriptEnginePrivate::agent() const
|
---|
2407 | {
|
---|
2408 | return m_agent;
|
---|
2409 | }
|
---|
2410 |
|
---|
2411 | void 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
|
---|
2419 | qint64 QScriptEnginePrivate::nextScriptId()
|
---|
2420 | {
|
---|
2421 | // ### reuse IDs by using a pool
|
---|
2422 | return m_scriptCounter++;
|
---|
2423 | }
|
---|
2424 |
|
---|
2425 | void 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 |
|
---|
2431 | void QScriptEnginePrivate::notifyScriptUnload_helper(qint64 id)
|
---|
2432 | {
|
---|
2433 | m_agent->scriptUnload(id);
|
---|
2434 | }
|
---|
2435 |
|
---|
2436 | void QScriptEnginePrivate::notifyPositionChange_helper(QScriptContextPrivate *ctx)
|
---|
2437 | {
|
---|
2438 | m_agent->positionChange(ctx->scriptId(), ctx->currentLine, ctx->currentColumn);
|
---|
2439 | }
|
---|
2440 |
|
---|
2441 | void QScriptEnginePrivate::notifyContextPush_helper()
|
---|
2442 | {
|
---|
2443 | m_agent->contextPush();
|
---|
2444 | }
|
---|
2445 |
|
---|
2446 | void QScriptEnginePrivate::notifyContextPop_helper()
|
---|
2447 | {
|
---|
2448 | m_agent->contextPop();
|
---|
2449 | }
|
---|
2450 |
|
---|
2451 | void QScriptEnginePrivate::notifyFunctionEntry_helper(QScriptContextPrivate *ctx)
|
---|
2452 | {
|
---|
2453 | m_agent->functionEntry(ctx->scriptId());
|
---|
2454 | }
|
---|
2455 |
|
---|
2456 | void QScriptEnginePrivate::notifyFunctionExit_helper(QScriptContextPrivate *ctx)
|
---|
2457 | {
|
---|
2458 | m_agent->functionExit(ctx->scriptId(), toPublic(ctx->returnValue()));
|
---|
2459 | }
|
---|
2460 |
|
---|
2461 | void QScriptEnginePrivate::notifyException_helper(QScriptContextPrivate *ctx)
|
---|
2462 | {
|
---|
2463 | bool hasHandler = (ctx->exceptionHandlerContext() != 0);
|
---|
2464 | m_agent->exceptionThrow(ctx->scriptId(), toPublic(ctx->returnValue()), hasHandler);
|
---|
2465 | }
|
---|
2466 |
|
---|
2467 | void QScriptEnginePrivate::notifyExceptionCatch_helper(QScriptContextPrivate *ctx)
|
---|
2468 | {
|
---|
2469 | m_agent->exceptionCatch(ctx->scriptId(), toPublic(ctx->returnValue()));
|
---|
2470 | }
|
---|
2471 |
|
---|
2472 | void 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 |
|
---|
2488 | QScriptString QScriptEnginePrivate::internedString(const QString &str)
|
---|
2489 | {
|
---|
2490 | return internedString(nameId(str, /*persistent=*/false));
|
---|
2491 | }
|
---|
2492 |
|
---|
2493 | QScriptString 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 |
|
---|
2509 | void 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 |
|
---|
2519 | QScriptValueImpl 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 |
|
---|
2534 | QScriptValueImpl 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 |
|
---|
2555 | int QScriptEnginePrivate::registerCustomClassType()
|
---|
2556 | {
|
---|
2557 | return ++m_class_prev_id;
|
---|
2558 | }
|
---|
2559 |
|
---|
2560 | QScriptValueImpl 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 |
|
---|
2575 | namespace QScript {
|
---|
2576 |
|
---|
2577 | static 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 |
|
---|
2625 | static QScriptValueImpl qTranslateNoOp(QScriptContextPrivate *ctx, QScriptEnginePrivate *, QScriptClassInfo *)
|
---|
2626 | {
|
---|
2627 | return ctx->argument(1);
|
---|
2628 | }
|
---|
2629 |
|
---|
2630 | static 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 |
|
---|
2666 | static QScriptValueImpl qTrNoOp(QScriptContextPrivate *ctx, QScriptEnginePrivate *, QScriptClassInfo *)
|
---|
2667 | {
|
---|
2668 | return ctx->argument(0);
|
---|
2669 | }
|
---|
2670 |
|
---|
2671 | } // namespace QScript
|
---|
2672 |
|
---|
2673 | void 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 |
|
---|
2693 | bool 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 |
|
---|
2700 | QScriptSyntaxCheckResult 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 |
|
---|
2722 | QT_END_NAMESPACE
|
---|
2723 |
|
---|
2724 | #endif // QT_NO_SCRIPT
|
---|