From 8a473230cbc1776ced4aa898c6d26241c48879bc Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Mon, 9 Jul 2012 23:41:56 -0700 Subject: [PATCH] Bug 772012: create a CompileError class. r=njn --- js/src/frontend/TokenStream.cpp | 151 +++++++++++++++----------------- js/src/frontend/TokenStream.h | 14 +++ 2 files changed, 87 insertions(+), 78 deletions(-) diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 93706e87e78..79021da8381 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -407,65 +407,87 @@ TokenStream::reportStrictModeErrorNumberVA(ParseNode *pn, unsigned errorNumber, return reportCompileErrorNumberVA(pn, flags, errorNumber, args); } +void +CompileError::throwError() +{ + /* + * If there's a runtime exception type associated with this error + * number, set that as the pending exception. For errors occuring at + * compile time, this is very likely to be a JSEXN_SYNTAXERR. + * + * If an exception is thrown but not caught, the JSREPORT_EXCEPTION + * flag will be set in report.flags. Proper behavior for an error + * reporter is to ignore a report with this flag for all but top-level + * compilation errors. The exception will remain pending, and so long + * as the non-top-level "load", "eval", or "compile" native function + * returns false, the top-level reporter will eventually receive the + * uncaught exception report. + */ + if (!js_ErrorToException(cx, message, &report, NULL, NULL)) { + /* + * If debugErrorHook is present then we give it a chance to veto + * sending the error on to the regular error reporter. + */ + bool reportError = true; + if (JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook) { + reportError = hook(cx, message, &report, cx->runtime->debugHooks.debugErrorHookData); + } + + /* Report the error */ + if (reportError && cx->errorReporter) + cx->errorReporter(cx, message, &report); + } +} + +CompileError::~CompileError() +{ + cx->free_((void*)report.uclinebuf); + cx->free_((void*)report.linebuf); + cx->free_((void*)report.ucmessage); + cx->free_(message); + message = NULL; + + if (report.messageArgs) { + if (hasCharArgs) { + unsigned i = 0; + while (report.messageArgs[i]) + cx->free_((void*)report.messageArgs[i++]); + } + cx->free_(report.messageArgs); + } + + PodZero(&report); +} + bool TokenStream::reportCompileErrorNumberVA(ParseNode *pn, unsigned flags, unsigned errorNumber, va_list args) { - class ReportManager - { - JSContext *cx; - JSErrorReport *report; - bool hasCharArgs; + bool strict = JSREPORT_IS_STRICT(flags); + bool warning = JSREPORT_IS_WARNING(flags); - public: - char *message; - - ReportManager(JSContext *cx, JSErrorReport *report, bool hasCharArgs) - : cx(cx), report(report), hasCharArgs(hasCharArgs), message(NULL) - {} - - ~ReportManager() { - cx->free_((void*)report->uclinebuf); - cx->free_((void*)report->linebuf); - cx->free_(message); - cx->free_((void*)report->ucmessage); - - if (report->messageArgs) { - if (hasCharArgs) { - unsigned i = 0; - while (report->messageArgs[i]) - cx->free_((void *)report->messageArgs[i++]); - } - cx->free_((void *)report->messageArgs); - } - } - }; - - if (JSREPORT_IS_STRICT(flags) && !cx->hasStrictOption()) + if (strict && !cx->hasStrictOption()) return true; - bool warning = JSREPORT_IS_WARNING(flags); if (warning && cx->hasWErrorOption()) { flags &= ~JSREPORT_WARNING; warning = false; } + CompileError normalError(cx); + CompileError *err = &normalError; const TokenPos *const tp = pn ? &pn->pn_pos : ¤tToken().pos; - JSErrorReport report; - PodZero(&report); - report.flags = flags; - report.errorNumber = errorNumber; - report.filename = filename; - report.originPrincipals = originPrincipals; - report.lineno = tp->begin.lineno; + err->report.flags = flags; + err->report.errorNumber = errorNumber; + err->report.filename = filename; + err->report.originPrincipals = originPrincipals; + err->report.lineno = tp->begin.lineno; - bool hasCharArgs = !(flags & JSREPORT_UC); + err->hasCharArgs = !(flags & JSREPORT_UC); - ReportManager mgr(cx, &report, hasCharArgs); - - if (!js_ExpandErrorArguments(cx, js_GetErrorMessage, NULL, errorNumber, &mgr.message, &report, - hasCharArgs, args)) { + if (!js_ExpandErrorArguments(cx, js_GetErrorMessage, NULL, errorNumber, &err->message, &err->report, + err->hasCharArgs, args)) { return false; } @@ -479,7 +501,7 @@ TokenStream::reportCompileErrorNumberVA(ParseNode *pn, unsigned flags, unsigned * means that any error involving a multi-line token (eg. an unterminated * multi-line string literal) won't have a context printed. */ - if (report.lineno == lineno) { + if (err->report.lineno == lineno) { const jschar *tokptr = linebase + tp->begin.index; // We show only a portion (a "window") of the line around the erroneous @@ -508,47 +530,20 @@ TokenStream::reportCompileErrorNumberVA(ParseNode *pn, unsigned flags, unsigned // Unicode and char versions of the window into the offending source // line, without final \n. - report.uclinebuf = windowBuf.extractWellSized(); - if (!report.uclinebuf) + err->report.uclinebuf = windowBuf.extractWellSized(); + if (!err->report.uclinebuf) return false; - report.linebuf = DeflateString(cx, report.uclinebuf, windowLength); - if (!report.linebuf) + err->report.linebuf = DeflateString(cx, err->report.uclinebuf, windowLength); + if (!err->report.linebuf) return false; // The lineno check above means we should only see single-line tokens here. JS_ASSERT(tp->begin.lineno == tp->end.lineno); - report.tokenptr = report.linebuf + windowIndex; - report.uctokenptr = report.uclinebuf + windowIndex; + err->report.tokenptr = err->report.linebuf + windowIndex; + err->report.uctokenptr = err->report.uclinebuf + windowIndex; } - /* - * If there's a runtime exception type associated with this error - * number, set that as the pending exception. For errors occuring at - * compile time, this is very likely to be a JSEXN_SYNTAXERR. - * - * If an exception is thrown but not caught, the JSREPORT_EXCEPTION - * flag will be set in report.flags. Proper behavior for an error - * reporter is to ignore a report with this flag for all but top-level - * compilation errors. The exception will remain pending, and so long - * as the non-top-level "load", "eval", or "compile" native function - * returns false, the top-level reporter will eventually receive the - * uncaught exception report. - */ - if (!js_ErrorToException(cx, mgr.message, &report, NULL, NULL)) { - /* - * If debugErrorHook is present then we give it a chance to veto - * sending the error on to the regular error reporter. - */ - bool reportError = true; - if (JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook) { - reportError = hook(cx, mgr.message, &report, - cx->runtime->debugHooks.debugErrorHookData); - } - - /* Report the error */ - if (reportError && cx->errorReporter) - cx->errorReporter(cx, mgr.message, &report); - } + err->throwError(); return warning; } diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 7f8457c0172..11b82e7b28b 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -413,6 +413,20 @@ enum TokenStreamFlags struct Parser; +struct CompileError { + JSContext *cx; + JSErrorReport report; + char *message; + bool hasCharArgs; + CompileError(JSContext *cx) + : cx(cx), message(NULL), hasCharArgs(false) + { + PodZero(&report); + } + ~CompileError(); + void throwError(); +}; + // Ideally, tokenizing would be entirely independent of context. But the // strict mode flag, which is in SharedContext, affects tokenizing, and // TokenStream needs to see it.