| 1 | /****************************************************************************
|
|---|
| 2 | **
|
|---|
| 3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|---|
| 4 | ** Contact: Qt Software Information (qt-info@nokia.com)
|
|---|
| 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 qt-sales@nokia.com.
|
|---|
| 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
|
|---|