如何从 v8 脚本编译错误中获取行号和列?

How can I get line number and column from v8 script compile error?

在C++项目中嵌入V8 Javascript引擎时,我没有找到任何方法来获取脚本编译失败的行号。我尝试了以下方法:

//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";
    }
}

转换为字符串时使用 v8::TryCatch::Exception 检索到的异常会导致如下错误消息:

SyntaxError: missing ) after argument list

消息中没有行号或列。使用 v8::TryCatch::StackTrace 转换为字符串时,我得到完全相同的消息,仍然没有行号。

v8::StackTrace::CurrentStackTrace 返回的堆栈跟踪不包含任何帧,所以我也无法在那里获取行号或列。

我也尝试在 v8::Script::Compile 函数中添加 v8::ScriptOrigin,但这并没有影响错误消息。

似乎行号存储在与异常关联的 v8::Message 中。
我在 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);
    }
  }
}