Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 3 files). Show all
Unified · Split
| @@ -556,7 +556,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 555 unmodified lines | ||
| 556 | 556 | } |
| 557 | 557 | |
| 558 | 558 | |
| 559 | −QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { | |
| 559 | +QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) { | |
| 560 | 560 | if (_stoppingAllScripts) { |
| 561 | 561 | return QScriptValue(); // bail early |
| 562 | 562 | } |
| @@ -565,27 +565,30 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN · 2 unmodified lines | ||
| 565 | 565 | QScriptValue result; |
| 566 | 566 | #ifdef THREAD_DEBUGGING |
| 567 | 567 | qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " |
| 568 | − "program:" << program << " fileName:" << fileName << "lineNumber:" << lineNumber; | |
| 568 | + "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; | |
| 569 | 569 | #endif |
| 570 | 570 | QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection, |
| 571 | 571 | Q_RETURN_ARG(QScriptValue, result), |
| 572 | − Q_ARG(const QString&, program), | |
| 572 | + Q_ARG(const QString&, sourceCode), | |
| 573 | 573 | Q_ARG(const QString&, fileName), |
| 574 | 574 | Q_ARG(int, lineNumber)); |
| 575 | 575 | return result; |
| 576 | 576 | } |
| 577 | − | |
| 578 | − _evaluatesPending++; | |
| 579 | − QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber); | |
| 580 | − if (hasUncaughtException()) { | |
| 581 | − int line = uncaughtExceptionLineNumber(); | |
| 582 | − qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << " : " << fileName << ") line" << line << ": " << result.toString(); | |
| 577 | + | |
| 578 | + // Check synthax | |
| 579 | + const QScriptProgram program(sourceCode, fileName, lineNumber); | |
| 580 | + if (!checkSynthax(program)) { | |
| 581 | + return QScriptValue(); | |
| 583 | 582 | } |
| 584 | − _evaluatesPending--; | |
| 583 | + | |
| 584 | + ++_evaluatesPending; | |
| 585 | + const auto result = QScriptEngine::evaluate(program); | |
| 586 | + --_evaluatesPending; | |
| 587 | + | |
| 588 | + const auto hadUncaughtException = checkExceptions(this, program.fileName()); | |
| 585 | 589 | if (_wantSignals) { |
| 586 | − emit evaluationFinished(result, hasUncaughtException()); | |
| 590 | + emit evaluationFinished(result, hadUncaughtException); | |
| 587 | 591 | } |
| 588 | − clearExceptions(); | |
| 589 | 592 | return result; |
| 590 | 593 | } |
| 591 | 594 | |
| @@ -603,7 +606,7 @@ void ScriptEngine::run() { · 11 unmodified lines | ||
| 603 | 606 | emit runningStateChanged(); |
| 604 | 607 | } |
| 605 | 608 | |
| 606 | − QScriptValue result = evaluate(_scriptContents); | |
| 609 | + QScriptValue result = evaluate(_scriptContents, _fileNameString); | |
| 607 | 610 | |
| 608 | 611 | QElapsedTimer startTime; |
| 609 | 612 | startTime.start(); |
| @@ -644,15 +647,6 @@ void ScriptEngine::run() { · 34 unmodified lines | ||
| 644 | 647 | qint64 now = usecTimestampNow(); |
| 645 | 648 | float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; |
| 646 | 649 | |
| 647 | − if (hasUncaughtException()) { | |
| 648 | − int line = uncaughtExceptionLineNumber(); | |
| 649 | − qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << uncaughtException().toString(); | |
| 650 | − if (_wantSignals) { | |
| 651 | − emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString()); | |
| 652 | − } | |
| 653 | − clearExceptions(); | |
| 654 | − } | |
| 655 | − | |
| 656 | 650 | if (!_isFinished) { |
| 657 | 651 | if (_wantSignals) { |
| 658 | 652 | emit update(deltaTime); |
| @@ -660,6 +654,7 @@ void ScriptEngine::run() { · 1 unmodified line | ||
| 660 | 654 | } |
| 661 | 655 | lastUpdate = now; |
| 662 | 656 | |
| 657 | + checkExceptions(this, _fileNameString); | |
| 663 | 658 | } |
| 664 | 659 | |
| 665 | 660 | stopAllTimers(); // make sure all our timers are stopped if the script is ending |
| @@ -896,6 +891,38 @@ void ScriptEngine::load(const QString& loadFile) { · 230 unmodified lines | ||
| 896 | 891 | } |
| 897 | 892 | } |
| 898 | 893 | |
| 894 | + | |
| 895 | +bool ScriptEngine::checkSynthax(const QScriptProgram& program) { | |
| 896 | + const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); | |
| 897 | + if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { | |
| 898 | + const auto error = syntaxCheck.errorMessage(); | |
| 899 | + const auto line = QString::number(syntaxCheck.errorLineNumber()); | |
| 900 | + const auto column = QString::number(syntaxCheck.errorColumnNumber()); | |
| 901 | + const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column); | |
| 902 | + qCWarning(scriptengine) << qPrintable(message); | |
| 903 | + return false; | |
| 904 | + } | |
| 905 | + return true; | |
| 906 | +} | |
| 907 | + | |
| 908 | +bool ScriptEngine::checkExceptions(QScriptEngine* engine, const QString& fileName) { | |
| 909 | + if (engine->hasUncaughtException()) { | |
| 910 | + const auto backtrace = engine->uncaughtExceptionBacktrace(); | |
| 911 | + const auto exception = engine->uncaughtException().toString(); | |
| 912 | + const auto line = QString::number(engine->uncaughtExceptionLineNumber()); | |
| 913 | + engine->clearExceptions(); | |
| 914 | + | |
| 915 | + auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); | |
| 916 | + if (!backtrace.empty()) { | |
| 917 | + static const auto lineSeparator = "\n "; | |
| 918 | + message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); | |
| 919 | + } | |
| 920 | + qCWarning(scriptengine) << qPrintable(message); | |
| 921 | + return false; | |
| 922 | + } | |
| 923 | + return true; | |
| 924 | +} | |
| 925 | + | |
| 899 | 926 | // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args |
| 900 | 927 | void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) { |
| 901 | 928 | if (QThread::currentThread() != thread()) { |
| @@ -1015,7 +1042,8 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 113 unmodified lines | ||
| 1015 | 1042 | lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch(); |
| 1016 | 1043 | } |
| 1017 | 1044 | |
| 1018 | − QScriptValue entityScriptConstructor = evaluate(contents); | |
| 1045 | + auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript"); | |
| 1046 | + QScriptValue entityScriptConstructor = evaluate(contents, fileName); | |
| 1019 | 1047 | QScriptValue entityScriptObject = entityScriptConstructor.construct(); |
| 1020 | 1048 | EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified }; |
| 1021 | 1049 | _entityScripts[entityID] = newDetails; |