| 20 | #include <locale> |
| 21 | |
| 22 | PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionStack, bool printStack) { |
| 23 | JS::ErrorReportBuilder reportBuilder(cx); |
| 24 | if (!reportBuilder.init(cx, exceptionStack, JS::ErrorReportBuilder::WithSideEffects /* may call the `toString` method if an object is thrown */)) { |
| 25 | return PyUnicode_FromString("Spidermonkey set an exception, but could not initialize the error report."); |
| 26 | } |
| 27 | |
| 28 | /** |
| 29 | * the resulting python error string will be in the format: |
| 30 | * "Error in file <filename>, on line <lineno>: |
| 31 | * <offending line of code if relevant, nothing if not> |
| 32 | * <if offending line is present, then a '^' pointing to the relevant token> |
| 33 | * <spidermonkey error message> |
| 34 | * Stack Track: |
| 35 | * <stack trace>" |
| 36 | * |
| 37 | */ |
| 38 | std::stringstream outStrStream; |
| 39 | |
| 40 | JSErrorReport *errorReport = reportBuilder.report(); |
| 41 | if (errorReport && !!errorReport->filename) { // `errorReport->filename` (the source file name) can be null |
| 42 | std::string offsetSpaces(errorReport->tokenOffset(), ' '); // number of spaces equal to tokenOffset |
| 43 | std::string linebuf; // the offending JS line of code (can be empty) |
| 44 | |
| 45 | /* *INDENT-OFF* */ |
| 46 | outStrStream << "Error in file " << errorReport->filename.c_str() |
| 47 | << ", on line " << errorReport->lineno |
| 48 | << ", column " << errorReport->column.oneOriginValue() << ":\n"; |
| 49 | /* *INDENT-ON* */ |
| 50 | if (errorReport->linebuf()) { |
| 51 | std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; |
| 52 | std::u16string u16linebuf(errorReport->linebuf()); |
| 53 | linebuf = convert.to_bytes(u16linebuf); |
| 54 | } |
| 55 | if (linebuf.size()) { |
| 56 | outStrStream << linebuf << "\n"; |
| 57 | outStrStream << offsetSpaces << "^\n"; |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | // print out the SpiderMonkey error message |
| 62 | outStrStream << reportBuilder.toStringResult().c_str() << "\n"; |
| 63 | |
| 64 | if (printStack) { |
| 65 | JS::RootedObject stackObj(cx, exceptionStack.stack()); |
| 66 | if (stackObj.get()) { |
| 67 | JS::RootedString stackStr(cx); |
| 68 | BuildStackString(cx, nullptr, stackObj, &stackStr, 2, js::StackFormat::SpiderMonkey); |
| 69 | JS::UniqueChars stackStrUtf8 = JS_EncodeStringToUTF8(cx, stackStr); |
| 70 | outStrStream << "Stack Trace:\n" << stackStrUtf8.get(); |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | return PyUnicode_FromString(outStrStream.str().c_str()); |
| 75 | } |
| 76 | |
| 77 | void setSpiderMonkeyException(JSContext *cx) { |
| 78 | if (PyErr_Occurred()) { // Check if a Python exception has already been set, otherwise `PyErr_SetString` would overwrite the exception set |
no test coverage detected