When embedding the V8 Javascript engine in a C++ project, I haven't found any way to get the line number for compilation failure of a script. I have tried the following:
//Given that v8 is initialized, isolate, context and script_source is setup.
v8::TryCatch try_catch{isolate};
//Compile the script from source
v8::Local<v8::Script> script;
if (!v8::Script::Compile(context, script_source).ToLocal(&script)) {
//Compilation failed
//Print exception from TryCatch
auto exc = try_catch.Exception();
v8::String::Utf8Value err{isolate, exc};
if (*err) {
std::cerr << "Exception: " << *err << std::endl;
}
//Print StackTrace from TryCatch
v8::Local<v8::Value> trace;
if (try_catch.StackTrace(context).ToLocal(&trace)) {
v8::String::Utf8Value trace_str{isolate, trace};
std::cerr << "Trace: " << *trace_str << std::endl;
}
//Print stack trace from isolate
auto stack = v8::StackTrace::CurrentStackTrace(isolate, 100);
std::cerr << "Stack trace:\n";
for (int i = 0; i < stack->GetFrameCount(); ++i) {
auto frame = stack->GetFrame(isolate, i);
v8::String::Utf8Value function_name{isolate, frame->GetFunctionName()};
std::cerr
<< "\tat "
<< function_name
<< " (line " << frame->GetLineNumber()
<< ", column " << frame->GetColumn() << ")\n";
}
}
The exception retrieved with v8::TryCatch::Exception
when converted to a string results in error messages like this:
SyntaxError: missing ) after argument list
No line number or column in the message. I get the exact same message when using the v8::TryCatch::StackTrace
converted to a string, still no line number.
The stack trace returned by v8::StackTrace::CurrentStackTrace
doesn't contain any frames, so I can't get the line number or column there either.
I also tried adding a v8::ScriptOrigin
to the v8::Script::Compile
function, but that did not affect the error message.
It seems the line number is stored in a v8::Message
associated with the exception.
I found the following in an example in the v8 repo:
void ReportException(v8::Isolate* isolate, v8::TryCatch* try_catch) {
v8::HandleScope handle_scope(isolate);
v8::String::Utf8Value exception(isolate, try_catch->Exception());
const char* exception_string = ToCString(exception);
v8::Local<v8::Message> message = try_catch->Message();
if (message.IsEmpty()) {
// V8 didn't provide any extra information about this error; just
// print the exception.
fprintf(stderr, "%s\n", exception_string);
} else {
// Print (filename):(line number): (message).
v8::String::Utf8Value filename(isolate,
message->GetScriptOrigin().ResourceName());
v8::Local<v8::Context> context(isolate->GetCurrentContext());
const char* filename_string = ToCString(filename);
int linenum = message->GetLineNumber(context).FromJust();
fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
// Print line of source code.
v8::String::Utf8Value sourceline(
isolate, message->GetSourceLine(context).ToLocalChecked());
const char* sourceline_string = ToCString(sourceline);
fprintf(stderr, "%s\n", sourceline_string);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn(context).FromJust();
for (int i = 0; i < start; i++) {
fprintf(stderr, " ");
}
int end = message->GetEndColumn(context).FromJust();
for (int i = start; i < end; i++) {
fprintf(stderr, "^");
}
fprintf(stderr, "\n");
v8::Local<v8::Value> stack_trace_string;
if (try_catch->StackTrace(context).ToLocal(&stack_trace_string) &&
stack_trace_string->IsString() &&
v8::Local<v8::String>::Cast(stack_trace_string)->Length() > 0) {
v8::String::Utf8Value stack_trace(isolate, stack_trace_string);
const char* stack_trace_string = ToCString(stack_trace);
fprintf(stderr, "%s\n", stack_trace_string);
}
}
}