diff --git a/Examples/Makefile.in b/Examples/Makefile.in index 4f20b83b8..027ce795e 100644 --- a/Examples/Makefile.in +++ b/Examples/Makefile.in @@ -525,7 +525,7 @@ ifeq (,$(V8)) JS_DLNK = @JSCOREDYNAMICLINKING@ else JS_INCLUDE = @JSV8INC@ - JS_DLNK = @JSCOREDYNAMICLINKING@ + JS_DLNK = @JSV8DYNAMICLINKING@ endif ifeq (,$(V8)) @@ -542,6 +542,19 @@ JSCXXSHARED = @JSCORECXXSHARED@ JSCFLAGS = @JSCORECFLAGS@ JSCXXFLAGS = @JSCXXFLAGS@ +JSEXE_SRC_DIR = $(TOP)/../Tools/javascript +JSEXE_SRC = $(JSEXE_SRC_DIR)/javascript.cxx $(JSEXE_SRC_DIR)/js_shell.cxx +JSEXE = $(TOP)/../Tools/javascript/javascript +ifeq (,$(V8)) + JSEXE_SRC = $(JSEXE_SRC_DIR)/javascript.cxx $(JSEXE_SRC_DIR)/js_shell.cxx $(JSEXE_SRC_DIR)/jsc_shell.cxx + JSEXE_OPTS = -jsc + JSEXE_FLAGS = -DUSE_JSC +else + JSEXE_SRC = $(JSEXE_SRC_DIR)/javascript.cxx $(JSEXE_SRC_DIR)/js_shell.cxx $(JSEXE_SRC_DIR)/v8_shell.cxx + JSEXE_OPTS = -v8 + JSEXE_FLAG = -DUSE_V8 +endif + # ---------------------------------------------------------------- # Build a javascript dynamically loadable module (C) # ---------------------------------------------------------------- @@ -564,14 +577,14 @@ javascript_cpp: $(SRCS) # Compile a javascript executable # ---------------------------------------------------------------- javascript_exe: $(SRCS) - $(CXX) $(CXXFLAGS) $(JS_INCLUDE) $(JSCXXSRCS) $(LIBS) $(JS_DLNK) -o $(JAVASCRIPT_EXE) + $(CXX) $(CXXFLAGS) $(JSEXE_FLAGS) $(JS_INCLUDE) $(LIBS) $(JSEXE_SRC) $(JS_DLNK) -o $(JSEXE) # ---------------------------------------------------------------- # Run the Compile a javascript executable # ---------------------------------------------------------------- javascript_run: $(SRCS) - env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH $(JAVASCRIPT_EXE) -l $(TARGET) $(JS_SCRIPT) + env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH $(JSEXE) $(JSEXE_OPTS) -l $(TARGET) $(JS_SCRIPT) # ----------------------------------------------------------------- # Cleaning the javascript examples diff --git a/Tools/javascript/javascript.cxx b/Tools/javascript/javascript.cxx index 9e7dd2809..798158ff0 100644 --- a/Tools/javascript/javascript.cxx +++ b/Tools/javascript/javascript.cxx @@ -1,217 +1,99 @@ - -#include #include +#include #include - #include #include #include -#include +#include "js_shell.h" -#include +#ifdef USE_JSC +extern JSShell* create_jsc_shell(); +#endif -using namespace std; - -static JSValueRef jsc_printstring(JSContextRef context,JSObjectRef object, JSObjectRef globalobj, size_t argc, const JSValueRef args[], JSValueRef* ex); -static char* jsccreateStringWithContentsOfFile(const char* fileName); -bool jsc_registerFunction(JSGlobalContextRef context, JSObjectRef object, const char* FunctionName,JSObjectCallAsFunctionCallback cbFunction); - -typedef void* HANDLE; -typedef int (*JSCIntializer)(JSGlobalContextRef context); - -void jsc_printError(JSContextRef, JSValueRef, const std::string&); +#ifdef USE_V8 +extern JSShell* create_v8_shell(); +#endif void print_usage() { - std::cout << "javascript [-l module] " << std::endl; + std::cout << "javascript [-i] [-jsc|-v8] [-l module] " << std::endl; } int main(int argc, char* argv[]) { - std::string scriptPath; - - std::vector module_names; - - std::vector loaded_modules; - std::vector module_initializers; + std::string scriptPath = ""; + std::vector module_names; - for (int idx = 1; idx < argc; ++idx) { - if(strcmp(argv[idx], "-l") == 0) { - idx++; - if(idx > argc) { - print_usage(); - exit(-1); - } - std::string module_name(argv[idx]); - module_names.push_back(module_name); - } else { - scriptPath = argv[idx]; + bool interactive = false; + JSShell* shell = 0; + + for (int idx = 1; idx < argc; ++idx) { + if(strcmp(argv[idx], "-l") == 0) { + idx++; + if(idx > argc) { + print_usage(); + exit(-1); } + std::string module_name(argv[idx]); + module_names.push_back(module_name); + } else if(strcmp(argv[idx], "-v8") == 0) { +#ifdef USE_V8 + shell = create_v8_shell(); +#else + std::cerr << "V8 support is not enabled" << std::endl; + exit(-1); +#endif + } else if(strcmp(argv[idx], "-jsc") == 0) { +#ifdef USE_JSC + shell = create_jsc_shell(); +#else + std::cerr << "JSC support is not enabled" << std::endl; + exit(-1); +#endif + } else if(strcmp(argv[idx], "-i") == 0) { + interactive = true; + } else { + scriptPath = argv[idx]; } - - for(std::vector::iterator it = module_names.begin(); - it != module_names.end(); ++it) { - std::string module_name = *it; - std::string lib_name = std::string("lib").append(module_name).append(".so"); - - HANDLE handle = dlopen(lib_name.c_str(), RTLD_LAZY); - if(handle == 0) { - std::cout << "Could not load library " << lib_name << ":" - << std::endl << dlerror() << std::endl; - continue; - } - - std::string symname; - symname.append(module_name).append("_initialize"); - - JSCIntializer init_function = reinterpret_cast((long) dlsym(handle, symname.c_str())); - if(init_function == 0) { - std::cout << "Could not find initializer function in module " << module_name << std::endl; - dlclose(handle); - continue; - } - - loaded_modules.push_back(handle); - module_initializers.push_back(init_function); - } - - static int failed; - - JSGlobalContextRef context = JSGlobalContextCreate(NULL); - JSObjectRef globalObject = JSContextGetGlobalObject(context); - - jsc_registerFunction(context, globalObject, "print", jsc_printstring); // Utility print function - - // Call module initializers - for(std::vector::iterator it = module_initializers.begin(); - it != module_initializers.end(); ++it) { - JSCIntializer init_function = *it; - init_function(context); - } - - // Evaluate the javascript - char* scriptContent = jsccreateStringWithContentsOfFile(scriptPath.c_str()); - JSStringRef jsScript; - - if(!scriptContent) { - printf("FAIL: runme script could not be loaded.\n"); - failed = 1; - } - else { - JSValueRef ex; - jsScript = JSStringCreateWithUTF8CString(scriptContent); - JSValueRef jsResult = JSEvaluateScript(context, jsScript, 0, 0, 0, &ex); - - if (!jsResult && ex) { - jsc_printError(context, ex, scriptPath); - failed = 1; - } - } - - if (scriptContent != NULL) { - free(scriptContent); - } - - JSStringRelease(jsScript); - - JSGlobalContextRelease(context); - globalObject = 0; - - for(std::vector::iterator it = loaded_modules.begin(); - it != loaded_modules.end(); ++it) { - HANDLE handle = *it; - dlclose(handle); - } - - if (failed) { - printf("FAIL: Some tests failed.\n"); - return 1; - } -} - -static JSValueRef jsc_printstring(JSContextRef context,JSObjectRef object, JSObjectRef globalobj, size_t argc, const JSValueRef args[], JSValueRef* ex) -{ - if (argc > 0) - { - JSStringRef string = JSValueToStringCopy(context, args[0], NULL); - size_t numChars = JSStringGetMaximumUTF8CStringSize(string); - char *stringUTF8 = new char[numChars]; - JSStringGetUTF8CString(string, stringUTF8, numChars); - printf("%s\n", stringUTF8); - - delete[] stringUTF8; - } - - return JSValueMakeUndefined(context); -} - -static char* jsccreateStringWithContentsOfFile(const char* fileName) -{ - char* buffer; - - size_t buffer_size = 0; - size_t buffer_capacity = 1024; - buffer = (char*)malloc(buffer_capacity); - - FILE* f = fopen(fileName, "r"); - if (!f) - { - fprintf(stderr, "Could not open file: %s\n", fileName); - return 0; - } - - while (!feof(f) && !ferror(f)) - { - buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f); - if (buffer_size == buffer_capacity) - { - // guarantees space for trailing '\0' - buffer_capacity *= 2; - buffer = (char*)realloc(buffer, buffer_capacity); - } - } - fclose(f); - buffer[buffer_size] = '\0'; - - return buffer; -} - -bool jsc_registerFunction(JSGlobalContextRef context, JSObjectRef object, - const char* functionName, JSObjectCallAsFunctionCallback callback) -{ - JSStringRef js_functionName = JSStringCreateWithUTF8CString(functionName); - JSObjectSetProperty(context, object, js_functionName, - JSObjectMakeFunctionWithCallback(context, js_functionName, callback), - kJSPropertyAttributeNone, NULL); - JSStringRelease(js_functionName); - return true; -} - -void jsc_printError(JSContextRef ctx, JSValueRef err, const std::string& sourceUrl) -{ - char *buffer; - - JSStringRef string = JSValueToStringCopy(ctx, err, 0); - size_t length = JSStringGetLength(string); - - buffer = (char*) malloc(length+1); - JSStringGetUTF8CString(string, buffer, length+1); - std::string errMsg(buffer); - JSStringRelease(string); - free(buffer); - - JSObjectRef errObj = JSValueToObject(ctx, err, 0); - - if(errObj == 0) { - return; } - // Note: usually you would also retrieve the property "sourceURL" - // though, it happened that this was always "" - JSStringRef lineKey = JSStringCreateWithUTF8CString("line"); - JSValueRef jsLine = JSObjectGetProperty(ctx, errObj, lineKey, 0); - int line = (int) JSValueToNumber(ctx, jsLine, 0); - JSStringRelease(lineKey); + + if (shell == 0) { +#ifdef USE_JSC + shell = create_jsc_shell(); +#else + std::cerr << "JSC support is not enabled" << std::endl; + exit(-1); +#endif + } + + bool failed = false; + for(std::vector::iterator it = module_names.begin(); + it != module_names.end(); ++it) { + std::string module_name = *it; - std::cerr << sourceUrl << ":" << line << ":" << errMsg << std::endl; - + bool success = shell->ImportModule(module_name); + failed |= !success; + } + + if (failed) { + delete shell; + printf("FAIL: Some modules could not be loaded.\n"); + return -1; + } + + if(interactive) { + failed = !(shell->RunShell()); + } else { + failed = !(shell->RunScript(scriptPath)); + } + + if (failed) { + delete shell; + printf("FAIL: Error during execution of script.\n"); + return 1; + } + + delete shell; + + return 0; } diff --git a/Tools/javascript/js_shell.cxx b/Tools/javascript/js_shell.cxx new file mode 100644 index 000000000..b2b8672a6 --- /dev/null +++ b/Tools/javascript/js_shell.cxx @@ -0,0 +1,95 @@ +#include "js_shell.h" + +#include +#include +#include +#include + +#ifdef __GNUC__ +#include +#define LOAD_LIBRARY(name) dlopen(name, RTLD_LAZY) +#define CLOSE_LIBRARY(handle) dlclose(handle) +#define LIBRARY_ERROR dlerror +#define LIBRARYFILE(name) std::string("lib").append(name).append(".so") +#else +#error "implement dll loading" +#endif + +JSShell::~JSShell() { + + for(std::vector::iterator it = loaded_modules.begin(); + it != loaded_modules.end(); ++it) { + HANDLE handle = *it; + CLOSE_LIBRARY(handle); + } + +} + +bool JSShell::ImportModule(const std::string& name) { + + std::string lib_name = LIBRARYFILE(name); + + HANDLE handle = LOAD_LIBRARY(lib_name.c_str()); + if(handle == 0) { + std::cout << "Could not load library " << lib_name << ":" + << std::endl << LIBRARY_ERROR() << std::endl; + return false; + } + + if(!RegisterModule(handle, name)) { + std::cout << "Could not find initializer function in " << lib_name << std::endl; + CLOSE_LIBRARY(handle); + return false; + } + + loaded_modules.push_back(handle); + + return true; +} + +bool JSShell::RunScript(const std::string& scriptPath) { + std::string source = ReadFile(scriptPath); + if(!InitializeEngine()) return false; + + if(!ExecuteScript(source, scriptPath)) { + return false; + } + + return DisposeEngine(); +} + +bool JSShell::RunShell() { + + if(!InitializeEngine()) return false; + + static const int kBufferSize = 1024; + while (true) { + char buffer[kBufferSize]; + printf("> "); + char* str = fgets(buffer, kBufferSize, stdin); + if (str == NULL) break; + std::string source(str); + ExecuteScript(source, "(shell)"); + } + printf("\n"); +} + +std::string JSShell::ReadFile(const std::string& fileName) +{ + std::string script; + + std::ifstream file(fileName.c_str()); + if (file.is_open()) { + while ( file.good() ) { + std::string line; + getline(file, line); + script.append(line); + script.append("\n"); + } + file.close(); + } else { + std::cout << "Unable to open file " << fileName << "." << std::endl; + } + + return script; +} diff --git a/Tools/javascript/js_shell.h b/Tools/javascript/js_shell.h new file mode 100644 index 000000000..96535a4c0 --- /dev/null +++ b/Tools/javascript/js_shell.h @@ -0,0 +1,49 @@ +#ifndef JS_SHELL_H +#define JS_SHELL_H + +#include +#include + +typedef void* HANDLE; + +class JSShell { + +public: + enum Engine { + JSC, + V8 + }; + +public: + + JSShell() {} + + virtual ~JSShell(); + + bool ImportModule(const std::string& name); + + virtual bool RunScript(const std::string& scriptPath); + + virtual bool RunShell(); + +protected: + + virtual bool RegisterModule(HANDLE library, const std::string& module_name) = 0; + + virtual bool InitializeEngine() = 0; + + virtual bool ExecuteScript(const std::string& source, const std::string& name) = 0; + + virtual bool DisposeEngine() = 0; + + static std::string ReadFile(const std::string& fileName); + +protected: + + std::vector loaded_modules; + +}; + +typedef JSShell* (*JSShellFactory)(); + +#endif // JS_SHELL_H diff --git a/Tools/javascript/jsc_shell.cxx b/Tools/javascript/jsc_shell.cxx new file mode 100644 index 000000000..3fa704440 --- /dev/null +++ b/Tools/javascript/jsc_shell.cxx @@ -0,0 +1,171 @@ +#include + +#include "js_shell.h" + +#include +#include + +#ifdef __GNUC__ +#include +#define LOAD_SYMBOL(handle, name) dlsym(handle, name) +#else +#error "implement dll loading" +#endif + +JSValueRef JSCShell_Print(JSContextRef context, JSObjectRef object, + JSObjectRef globalobj, size_t argc, + const JSValueRef args[], JSValueRef* ex); + +class JSCShell: public JSShell { + +typedef int (*JSCIntializer)(JSGlobalContextRef context); + +public: + + JSCShell() {}; + + virtual ~JSCShell(); + +protected: + + virtual bool RegisterModule(HANDLE library, const std::string& module_name); + + virtual bool InitializeEngine(); + + virtual bool ExecuteScript(const std::string& source, const std::string& name); + + virtual bool DisposeEngine(); + +private: + + //static JSValueRef Print(JSContextRef context,JSObjectRef object, JSObjectRef globalobj, size_t argc, const JSValueRef args[], JSValueRef* ex); + + static bool RegisterFunction(JSGlobalContextRef context, JSObjectRef object, const char* functionName, JSObjectCallAsFunctionCallback cbFunction); + + static void PrintError(JSContextRef, JSValueRef, const std::string&); + +private: + + std::vector module_initializers; + + JSGlobalContextRef context; +}; + +using namespace std; + +JSCShell::~JSCShell() { + if(context != 0) { + JSGlobalContextRelease(context); + context = 0; + } +} + +bool JSCShell::RegisterModule(HANDLE library, const std::string& module_name) { + std::string symname = std::string(module_name).append("_initialize"); + + JSCIntializer init_function = reinterpret_cast((long) LOAD_SYMBOL(library, symname.c_str())); + if(init_function == 0) return false; + + module_initializers.push_back(init_function); + return true; +} + +bool JSCShell::InitializeEngine() { + if(context != 0) { + JSGlobalContextRelease(context); + context = 0; + } + // TODO: check for initialization errors + context = JSGlobalContextCreate(NULL); + if(context == 0) return false; + JSObjectRef globalObject = JSContextGetGlobalObject(context); + JSCShell::RegisterFunction(context, globalObject, "print", JSCShell_Print); + // Call module initializers + for(std::vector::iterator it = module_initializers.begin(); + it != module_initializers.end(); ++it) { + JSCIntializer init_function = *it; + if(!init_function(context)) { + return false; + } + } + return true; +} + +bool JSCShell::ExecuteScript(const std::string& source, const std::string& name) { + JSStringRef jsScript; + JSValueRef ex; + jsScript = JSStringCreateWithUTF8CString(source.c_str()); + JSValueRef jsResult = JSEvaluateScript(context, jsScript, 0, 0, 0, &ex); + JSStringRelease(jsScript); + if (jsResult == NULL && ex != NULL) { + JSCShell::PrintError(context, ex, name); + return false; + } + return true; +} + +bool JSCShell::DisposeEngine() { + JSGlobalContextRelease(context); + context = 0; + return true; +} + +JSValueRef JSCShell_Print(JSContextRef context, JSObjectRef object, + JSObjectRef globalobj, size_t argc, + const JSValueRef args[], JSValueRef* ex) { + if (argc > 0) + { + JSStringRef string = JSValueToStringCopy(context, args[0], NULL); + size_t numChars = JSStringGetMaximumUTF8CStringSize(string); + char *stringUTF8 = new char[numChars]; + JSStringGetUTF8CString(string, stringUTF8, numChars); + printf("%s\n", stringUTF8); + + delete[] stringUTF8; + } + + return JSValueMakeUndefined(context); +} + +bool JSCShell::RegisterFunction(JSGlobalContextRef context, JSObjectRef object, + const char* functionName, JSObjectCallAsFunctionCallback callback) { + JSStringRef js_functionName = JSStringCreateWithUTF8CString(functionName); + JSObjectSetProperty(context, object, js_functionName, + JSObjectMakeFunctionWithCallback(context, js_functionName, callback), + kJSPropertyAttributeNone, NULL); + JSStringRelease(js_functionName); + return true; +} + +void JSCShell::PrintError(JSContextRef ctx, JSValueRef err, const std::string& name) { + char *buffer; + + JSStringRef string = JSValueToStringCopy(ctx, err, 0); + size_t length = JSStringGetLength(string); + + buffer = new char[length+1]; + JSStringGetUTF8CString(string, buffer, length+1); + std::string errMsg(buffer); + JSStringRelease(string); + delete[] buffer; + + JSObjectRef errObj = JSValueToObject(ctx, err, 0); + + if(errObj == 0) { + std::cerr << errMsg << std::endl; + return; + } + + // Note: usually you would also retrieve the property "sourceURL" + // though, it happened that this was always "" + JSStringRef lineKey = JSStringCreateWithUTF8CString("line"); + JSValueRef jsLine = JSObjectGetProperty(ctx, errObj, lineKey, 0); + int line = (int) JSValueToNumber(ctx, jsLine, 0); + JSStringRelease(lineKey); + + std::cerr << name << ":" << line << ":" << errMsg << std::endl; +} + +JSShell* create_jsc_shell() { + return new JSCShell(); +} diff --git a/Tools/javascript/v8_shell.cxx b/Tools/javascript/v8_shell.cxx new file mode 100755 index 000000000..940609ec3 --- /dev/null +++ b/Tools/javascript/v8_shell.cxx @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "js_shell.h" + +typedef int (*V8ExtensionRegistrar) (v8::Handle); + +class V8Shell: public JSShell { + +public: + V8Shell(); + + virtual ~V8Shell(); + +protected: + + virtual bool RegisterModule(HANDLE library, const std::string& module_name); + + virtual bool InitializeEngine(); + + virtual bool ExecuteScript(const std::string& source, const std::string& name); + + virtual bool DisposeEngine(); + +private: + + v8::Persistent CreateShellContext(); + + void ReportException(v8::TryCatch* handler); + + static v8::Handle Print(const v8::Arguments& args); + + static v8::Handle Quit(const v8::Arguments& args); + + static v8::Handle Version(const v8::Arguments& args); + + static const char* ToCString(const v8::String::Utf8Value& value); + +protected: + + std::vector module_initializers; + + v8::Persistent context; + +}; + +#ifdef __GNUC__ +#include +#define LOAD_SYMBOL(handle, name) dlsym(handle, name) +#else +#error "implement dll loading" +#endif + +// Extracts a C string from a V8 Utf8Value. +const char* V8Shell::ToCString(const v8::String::Utf8Value& value) { + return *value ? *value : ""; +} + +V8Shell::V8Shell() +{ +} + +V8Shell::~V8Shell() { + context.Dispose(); + v8::V8::Dispose(); +} + +bool V8Shell::RegisterModule(HANDLE library, const std::string& module_name) { + std::string symname = std::string(module_name).append("_initialize"); + + V8ExtensionRegistrar init_function = reinterpret_cast((long) LOAD_SYMBOL(library, symname.c_str())); + if(init_function == 0) return false; + + module_initializers.push_back(init_function); + return true; +} + +bool V8Shell::InitializeEngine() { + if (!context.IsEmpty()) { + context.Dispose(); + } + + context = CreateShellContext(); + if (context.IsEmpty()) { + printf("Could not create context.\n"); + return 1; + } + + context->Enter(); +} + +bool V8Shell::ExecuteScript(const std::string& source, const std::string& name) { + // Enter the execution environment before evaluating any code. + v8::Context::Scope context_scope(context); + + v8::HandleScope handle_scope; + v8::TryCatch try_catch; + v8::Handle script = v8::Script::Compile(v8::String::New(source.c_str()), v8::String::New(name.c_str())); + if (script.IsEmpty()) { + // Print errors that happened during compilation. + ReportException(&try_catch); + return false; + } else { + v8::Handle result = script->Run(); + if (result.IsEmpty()) { + assert(try_catch.HasCaught()); + // Print errors that happened during execution. + ReportException(&try_catch); + return false; + } else { + assert(!try_catch.HasCaught()); + if (!result->IsUndefined()) { + // If all went well and the result wasn't undefined then print + // the returned value. + v8::String::Utf8Value str(result); + const char* cstr = V8Shell::ToCString(str); + printf("%s\n", cstr); + } + return true; + } + } +} + +bool V8Shell::DisposeEngine() { + context->Exit(); + context.Dispose(); + v8::V8::Dispose(); +} + +v8::Persistent V8Shell::CreateShellContext() { + // Create a template for the global object. + v8::Handle global = v8::ObjectTemplate::New(); + + // Bind global functions + global->Set(v8::String::New("print"), v8::FunctionTemplate::New(V8Shell::Print)); + global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(V8Shell::Quit)); + global->Set(v8::String::New("version"), v8::FunctionTemplate::New(V8Shell::Version)); + + v8::Persistent _context = v8::Context::New(NULL, global); + + // register extensions + for(std::vector::iterator it=module_initializers.begin(); + it != module_initializers.end(); ++it) { + (*it)(_context); + } + + return _context; +} + + +v8::Handle V8Shell::Print(const v8::Arguments& args) { + bool first = true; + for (int i = 0; i < args.Length(); i++) { + v8::HandleScope handle_scope; + if (first) { + first = false; + } else { + printf(" "); + } + v8::String::Utf8Value str(args[i]); + const char* cstr = V8Shell::ToCString(str); + printf("%s", cstr); + } + printf("\n"); + fflush(stdout); + return v8::Undefined(); +} + +v8::Handle V8Shell::Quit(const v8::Arguments& args) { + int exit_code = args[0]->Int32Value(); + fflush(stdout); + fflush(stderr); + exit(exit_code); + return v8::Undefined(); +} + +v8::Handle V8Shell::Version(const v8::Arguments& args) { + return v8::String::New(v8::V8::GetVersion()); +} + +void V8Shell::ReportException(v8::TryCatch* try_catch) { + v8::HandleScope handle_scope; + v8::String::Utf8Value exception(try_catch->Exception()); + const char* exception_string = V8Shell::ToCString(exception); + v8::Handle message = try_catch->Message(); + if (message.IsEmpty()) { + // V8 didn't provide any extra information about this error; just + // print the exception. + printf("%s\n", exception_string); + } else { + // Print (filename):(line number): (message). + v8::String::Utf8Value filename(message->GetScriptResourceName()); + const char* filename_string = V8Shell::ToCString(filename); + int linenum = message->GetLineNumber(); + printf("%s:%i: %s\n", filename_string, linenum, exception_string); + // Print line of source code. + v8::String::Utf8Value sourceline(message->GetSourceLine()); + const char* sourceline_string = V8Shell::ToCString(sourceline); + printf("%s\n", sourceline_string); + // Print wavy underline (GetUnderline is deprecated). + int start = message->GetStartColumn(); + for (int i = 0; i < start; i++) { + printf(" "); + } + int end = message->GetEndColumn(); + for (int i = start; i < end; i++) { + printf("^"); + } + printf("\n"); + v8::String::Utf8Value stack_trace(try_catch->StackTrace()); + if (stack_trace.length() > 0) { + const char* stack_trace_string = V8Shell::ToCString(stack_trace); + printf("%s\n", stack_trace_string); + } + } +}