| 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 | 
|---|