diff --git a/libraries/script-engine/src/ConsoleScriptingInterface.cpp b/libraries/script-engine/src/ConsoleScriptingInterface.cpp index ed2fcfadcc..c4c59f2f94 100644 --- a/libraries/script-engine/src/ConsoleScriptingInterface.cpp +++ b/libraries/script-engine/src/ConsoleScriptingInterface.cpp @@ -52,10 +52,46 @@ void ConsoleScriptingInterface::error(QString message) { void ConsoleScriptingInterface::exception(QString message) { if (ScriptEngine* scriptEngine = qobject_cast(engine())) { - scriptEngine->scriptErrorMessage(message); + scriptEngine->logConsoleException(message); } + } +bool ConsoleScriptingInterface:: hasCorrectSyntax(QScriptProgram& program) { + const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); + if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { + const auto error = syntaxCheck.errorMessage(); + const auto line = QString::number(syntaxCheck.errorLineNumber()); + const auto column = QString::number(syntaxCheck.errorColumnNumber()); + const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column); + qCritical() << qPrintable(message); + return false; + } + return true; +} + +QString ConsoleScriptingInterface::hadUncaughtExceptions(QScriptEngine& engine, QString& fileName) { + log("4"); + //if (engine.hasUncaughtException()) { + const auto backtrace = engine.uncaughtExceptionBacktrace(); + const auto exception = engine.uncaughtException().toString(); + const auto line = QString::number(engine.uncaughtExceptionLineNumber()); + engine.clearExceptions(); + log("5"); + static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3"; + auto message = QString(SCRIPT_EXCEPTION_FORMAT).arg(exception, fileName, line); + if (!backtrace.empty()) { + static const auto lineSeparator = "\n "; + message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); + } + // qCritical() << qPrintable(message); + log("6"); + return message; + //} + //return false; +} + + void ConsoleScriptingInterface::time(QString labelName) { QDateTime _currentTime = QDateTime::currentDateTime().toUTC(); _listOfTimeValues.insert(labelName, _currentTime.toUTC()); @@ -126,9 +162,9 @@ void ConsoleScriptingInterface::asserts(bool condition, QString message) { } } -void ConsoleScriptingInterface::trace(QString labelName) { +void ConsoleScriptingInterface::trace() { if (ScriptEngine* scriptEngine = qobject_cast(engine())) { - scriptEngine->scriptErrorMessage(labelName); + scriptEngine->logTraceException(); } } diff --git a/libraries/script-engine/src/ConsoleScriptingInterface.h b/libraries/script-engine/src/ConsoleScriptingInterface.h index c281139fea..1dad4d8440 100644 --- a/libraries/script-engine/src/ConsoleScriptingInterface.h +++ b/libraries/script-engine/src/ConsoleScriptingInterface.h @@ -22,6 +22,8 @@ #include #include #include +#include "EntityEditFilters.h" +#include #include @@ -38,15 +40,16 @@ public slots: void time(QString labelName); void timeEnd(QString labelName); void asserts(bool condition, QString message = ""); - void trace(QString labelName); + void trace(); void clear(); void group(QString groupName); void groupCollapsed(QString groupName); void groupEnd(); void consoleGroupLog(QString currentGroup, QString groupName); public: - QString secondsToString(qint64 seconds); - bool isInteger(const std::string & s); + QString secondsToString(qint64 seconds); + bool hasCorrectSyntax(QScriptProgram& program); + QString hadUncaughtExceptions(QScriptEngine& engine, QString& fileName); private: QHash _listOfTimeValues; const qint64 DAY = 86400; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 5c7ca6aadc..34048ff9c4 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -145,6 +145,17 @@ QString encodeEntityIdIntoEntityUrl(const QString& url, const QString& entityID) return url + " [EntityID:" + entityID + "]"; } +void ScriptEngine::logConsoleException(QString message) { + this->raiseConsoleException(this->makeError(message)); +} + +QString ScriptEngine::logTraceException() { + QScriptValue value = this->raiseConsoleTraceException(this->makeError("")); + auto trace = formatTrace(value, _enableExtendedJSExceptions.get()); + scriptInfoMessage(trace); + return trace; +} + QString ScriptEngine::logException(const QScriptValue& exception) { auto message = formatException(exception, _enableExtendedJSExceptions.get()); scriptErrorMessage(message); @@ -187,6 +198,15 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const } logException(output); }); + + // this is where all unhandled exceptions end up getting logged + /* connect(this, &BaseScriptEngine::unhandledException, this, [this](const QScriptValue& err) { + auto output = err.engine() == this ? err : makeError(err); + if (!output.property("detail").isValid()) { + output.setProperty("detail", "UnhandledException"); + } + logException(output); + });*/ } QString ScriptEngine::getContext() const { diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index c3b97b7f9e..590c75f759 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -148,7 +148,8 @@ public: /// to scripts. we may not need this to be invokable void loadURL(const QUrl& scriptURL, bool reload); bool hasValidScriptSuffix(const QString& scriptFileName); - + void logConsoleException(QString message); + QString logTraceException(); Q_INVOKABLE QString getContext() const; Q_INVOKABLE bool isClientScript() const { return _context == CLIENT_SCRIPT; } Q_INVOKABLE bool isEntityClientScript() const { return _context == ENTITY_CLIENT_SCRIPT; } diff --git a/libraries/shared/src/BaseScriptEngine.cpp b/libraries/shared/src/BaseScriptEngine.cpp index c92d629b75..711af818e6 100644 --- a/libraries/shared/src/BaseScriptEngine.cpp +++ b/libraries/shared/src/BaseScriptEngine.cpp @@ -22,6 +22,7 @@ #include "Profile.h" const QString BaseScriptEngine::SCRIPT_EXCEPTION_FORMAT { "[%0] %1 in %2:%3" }; +const QString BaseScriptEngine::SCRIPT_TRACE_FORMAT{ "[%0] %1" }; const QString BaseScriptEngine::SCRIPT_BACKTRACE_SEP { "\n " }; bool BaseScriptEngine::IS_THREADSAFE_INVOCATION(const QThread *thread, const QString& method) { @@ -159,7 +160,7 @@ QScriptValue BaseScriptEngine::cloneUncaughtException(const QString& extraDetail #endif return err; } - + QString BaseScriptEngine::formatException(const QScriptValue& exception, bool includeExtendedDetails) { if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return QString(); @@ -192,6 +193,27 @@ QString BaseScriptEngine::formatException(const QScriptValue& exception, bool in return result; } +QString BaseScriptEngine::formatTrace(const QScriptValue& value, bool includeExtendedDetails) { + if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { + return QString(); + } + QString note{ "TRACE" }; + QString result; + + if (!value.isObject()) { + return result; + } + const auto fileName = value.property("fileName").toString(); + const auto lineNumber = value.property("lineNumber").toString(); + const auto stacktrace = value.property("stack").toString(); + + result = QString(SCRIPT_TRACE_FORMAT).arg(fileName, lineNumber); + if (!stacktrace.isEmpty()) { + result += QString("\n[Trace]%1%2").arg(SCRIPT_BACKTRACE_SEP).arg(stacktrace); + } + return result; +} + bool BaseScriptEngine::raiseException(const QScriptValue& exception) { if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return false; @@ -208,6 +230,18 @@ bool BaseScriptEngine::raiseException(const QScriptValue& exception) { return false; } +void BaseScriptEngine::raiseConsoleException(const QScriptValue& exception) { + if (currentContext()) { + currentContext()->throwValue(makeError(exception)); + } +} + +QScriptValue BaseScriptEngine::raiseConsoleTraceException(const QScriptValue& exception) { + if (currentContext()) { + return currentContext()->throwValue(makeError(exception)); + } +} + bool BaseScriptEngine::maybeEmitUncaughtException(const QString& debugHint) { if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return false; diff --git a/libraries/shared/src/BaseScriptEngine.h b/libraries/shared/src/BaseScriptEngine.h index 138e46fafa..fee65896b8 100644 --- a/libraries/shared/src/BaseScriptEngine.h +++ b/libraries/shared/src/BaseScriptEngine.h @@ -21,6 +21,7 @@ class BaseScriptEngine : public QScriptEngine, public QEnableSharedFromThis