Bug 772012: create a CompileError class. r=njn

This commit is contained in:
Benjamin Peterson 2012-07-09 23:41:56 -07:00
parent 5931a642f4
commit 8a473230cb
2 changed files with 87 additions and 78 deletions

View File

@ -407,65 +407,87 @@ TokenStream::reportStrictModeErrorNumberVA(ParseNode *pn, unsigned errorNumber,
return reportCompileErrorNumberVA(pn, flags, errorNumber, args); 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 bool
TokenStream::reportCompileErrorNumberVA(ParseNode *pn, unsigned flags, unsigned errorNumber, TokenStream::reportCompileErrorNumberVA(ParseNode *pn, unsigned flags, unsigned errorNumber,
va_list args) va_list args)
{ {
class ReportManager bool strict = JSREPORT_IS_STRICT(flags);
{ bool warning = JSREPORT_IS_WARNING(flags);
JSContext *cx;
JSErrorReport *report;
bool hasCharArgs;
public: if (strict && !cx->hasStrictOption())
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())
return true; return true;
bool warning = JSREPORT_IS_WARNING(flags);
if (warning && cx->hasWErrorOption()) { if (warning && cx->hasWErrorOption()) {
flags &= ~JSREPORT_WARNING; flags &= ~JSREPORT_WARNING;
warning = false; warning = false;
} }
CompileError normalError(cx);
CompileError *err = &normalError;
const TokenPos *const tp = pn ? &pn->pn_pos : &currentToken().pos; const TokenPos *const tp = pn ? &pn->pn_pos : &currentToken().pos;
JSErrorReport report; err->report.flags = flags;
PodZero(&report); err->report.errorNumber = errorNumber;
report.flags = flags; err->report.filename = filename;
report.errorNumber = errorNumber; err->report.originPrincipals = originPrincipals;
report.filename = filename; err->report.lineno = tp->begin.lineno;
report.originPrincipals = originPrincipals;
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, &err->message, &err->report,
err->hasCharArgs, args)) {
if (!js_ExpandErrorArguments(cx, js_GetErrorMessage, NULL, errorNumber, &mgr.message, &report,
hasCharArgs, args)) {
return false; 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 * means that any error involving a multi-line token (eg. an unterminated
* multi-line string literal) won't have a context printed. * 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; const jschar *tokptr = linebase + tp->begin.index;
// We show only a portion (a "window") of the line around the erroneous // 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 // Unicode and char versions of the window into the offending source
// line, without final \n. // line, without final \n.
report.uclinebuf = windowBuf.extractWellSized(); err->report.uclinebuf = windowBuf.extractWellSized();
if (!report.uclinebuf) if (!err->report.uclinebuf)
return false; return false;
report.linebuf = DeflateString(cx, report.uclinebuf, windowLength); err->report.linebuf = DeflateString(cx, err->report.uclinebuf, windowLength);
if (!report.linebuf) if (!err->report.linebuf)
return false; return false;
// The lineno check above means we should only see single-line tokens here. // The lineno check above means we should only see single-line tokens here.
JS_ASSERT(tp->begin.lineno == tp->end.lineno); JS_ASSERT(tp->begin.lineno == tp->end.lineno);
report.tokenptr = report.linebuf + windowIndex; err->report.tokenptr = err->report.linebuf + windowIndex;
report.uctokenptr = report.uclinebuf + windowIndex; err->report.uctokenptr = err->report.uclinebuf + windowIndex;
} }
/* err->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, 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);
}
return warning; return warning;
} }

View File

@ -413,6 +413,20 @@ enum TokenStreamFlags
struct Parser; 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 // Ideally, tokenizing would be entirely independent of context. But the
// strict mode flag, which is in SharedContext, affects tokenizing, and // strict mode flag, which is in SharedContext, affects tokenizing, and
// TokenStream needs to see it. // TokenStream needs to see it.