1 // Copyright 2009 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include <v8.h> 29 #include <fcntl.h> 30 #include <string.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 34 35 void RunShell(v8::Handle<v8::Context> context); 36 bool ExecuteString(v8::Handle<v8::String> source, 37 v8::Handle<v8::Value> name, 38 bool print_result, 39 bool report_exceptions); 40 v8::Handle<v8::Value> Print(const v8::Arguments& args); 41 v8::Handle<v8::Value> Read(const v8::Arguments& args); 42 v8::Handle<v8::Value> Load(const v8::Arguments& args); 43 v8::Handle<v8::Value> Quit(const v8::Arguments& args); 44 v8::Handle<v8::Value> Version(const v8::Arguments& args); 45 v8::Handle<v8::String> ReadFile(const char* name); 46 void ReportException(v8::TryCatch* handler); 47 48 49 int RunMain(int argc, char* argv[]) { 50 v8::V8::SetFlagsFromCommandLine(&argc, argv, true); 51 v8::HandleScope handle_scope; 52 // Create a template for the global object. 53 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); 54 // Bind the global 'print' function to the C++ Print callback. 55 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print)); 56 // Bind the global 'read' function to the C++ Read callback. 57 global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read)); 58 // Bind the global 'load' function to the C++ Load callback. 59 global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load)); 60 // Bind the 'quit' function 61 global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit)); 62 // Bind the 'version' function 63 global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version)); 64 // Create a new execution environment containing the built-in 65 // functions 66 v8::Handle<v8::Context> context = v8::Context::New(NULL, global); 67 // Enter the newly created execution environment. 68 v8::Context::Scope context_scope(context); 69 bool run_shell = (argc == 1); 70 for (int i = 1; i < argc; i++) { 71 const char* str = argv[i]; 72 if (strcmp(str, "--shell") == 0) { 73 run_shell = true; 74 } else if (strcmp(str, "-f") == 0) { 75 // Ignore any -f flags for compatibility with the other stand- 76 // alone JavaScript engines. 77 continue; 78 } else if (strncmp(str, "--", 2) == 0) { 79 printf("Warning: unknown flag %s.\nTry --help for options\n", str); 80 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) { 81 // Execute argument given to -e option directly 82 v8::HandleScope handle_scope; 83 v8::Handle<v8::String> file_name = v8::String::New("unnamed"); 84 v8::Handle<v8::String> source = v8::String::New(argv[i + 1]); 85 if (!ExecuteString(source, file_name, false, true)) 86 return 1; 87 i++; 88 } else { 89 // Use all other arguments as names of files to load and run. 90 v8::HandleScope handle_scope; 91 v8::Handle<v8::String> file_name = v8::String::New(str); 92 v8::Handle<v8::String> source = ReadFile(str); 93 if (source.IsEmpty()) { 94 printf("Error reading '%s'\n", str); 95 return 1; 96 } 97 if (!ExecuteString(source, file_name, false, true)) 98 return 1; 99 } 100 } 101 if (run_shell) RunShell(context); 102 return 0; 103 } 104 105 106 int main(int argc, char* argv[]) { 107 int result = RunMain(argc, argv); 108 v8::V8::Dispose(); 109 return result; 110 } 111 112 113 // Extracts a C string from a V8 Utf8Value. 114 const char* ToCString(const v8::String::Utf8Value& value) { 115 return *value ? *value : "<string conversion failed>"; 116 } 117 118 119 // The callback that is invoked by v8 whenever the JavaScript 'print' 120 // function is called. Prints its arguments on stdout separated by 121 // spaces and ending with a newline. 122 v8::Handle<v8::Value> Print(const v8::Arguments& args) { 123 bool first = true; 124 for (int i = 0; i < args.Length(); i++) { 125 v8::HandleScope handle_scope; 126 if (first) { 127 first = false; 128 } else { 129 printf(" "); 130 } 131 v8::String::Utf8Value str(args[i]); 132 const char* cstr = ToCString(str); 133 printf("%s", cstr); 134 } 135 printf("\n"); 136 fflush(stdout); 137 return v8::Undefined(); 138 } 139 140 141 // The callback that is invoked by v8 whenever the JavaScript 'read' 142 // function is called. This function loads the content of the file named in 143 // the argument into a JavaScript string. 144 v8::Handle<v8::Value> Read(const v8::Arguments& args) { 145 if (args.Length() != 1) { 146 return v8::ThrowException(v8::String::New("Bad parameters")); 147 } 148 v8::String::Utf8Value file(args[0]); 149 if (*file == NULL) { 150 return v8::ThrowException(v8::String::New("Error loading file")); 151 } 152 v8::Handle<v8::String> source = ReadFile(*file); 153 if (source.IsEmpty()) { 154 return v8::ThrowException(v8::String::New("Error loading file")); 155 } 156 return source; 157 } 158 159 160 // The callback that is invoked by v8 whenever the JavaScript 'load' 161 // function is called. Loads, compiles and executes its argument 162 // JavaScript file. 163 v8::Handle<v8::Value> Load(const v8::Arguments& args) { 164 for (int i = 0; i < args.Length(); i++) { 165 v8::HandleScope handle_scope; 166 v8::String::Utf8Value file(args[i]); 167 if (*file == NULL) { 168 return v8::ThrowException(v8::String::New("Error loading file")); 169 } 170 v8::Handle<v8::String> source = ReadFile(*file); 171 if (source.IsEmpty()) { 172 return v8::ThrowException(v8::String::New("Error loading file")); 173 } 174 if (!ExecuteString(source, v8::String::New(*file), false, false)) { 175 return v8::ThrowException(v8::String::New("Error executing file")); 176 } 177 } 178 return v8::Undefined(); 179 } 180 181 182 // The callback that is invoked by v8 whenever the JavaScript 'quit' 183 // function is called. Quits. 184 v8::Handle<v8::Value> Quit(const v8::Arguments& args) { 185 // If not arguments are given args[0] will yield undefined which 186 // converts to the integer value 0. 187 int exit_code = args[0]->Int32Value(); 188 exit(exit_code); 189 return v8::Undefined(); 190 } 191 192 193 v8::Handle<v8::Value> Version(const v8::Arguments& args) { 194 return v8::String::New(v8::V8::GetVersion()); 195 } 196 197 198 // Reads a file into a v8 string. 199 v8::Handle<v8::String> ReadFile(const char* name) { 200 FILE* file = fopen(name, "rb"); 201 if (file == NULL) return v8::Handle<v8::String>(); 202 203 fseek(file, 0, SEEK_END); 204 int size = ftell(file); 205 rewind(file); 206 207 char* chars = new char[size + 1]; 208 chars[size] = '\0'; 209 for (int i = 0; i < size;) { 210 int read = fread(&chars[i], 1, size - i, file); 211 i += read; 212 } 213 fclose(file); 214 v8::Handle<v8::String> result = v8::String::New(chars, size); 215 delete[] chars; 216 return result; 217 } 218 219 220 // The read-eval-execute loop of the shell. 221 void RunShell(v8::Handle<v8::Context> context) { 222 printf("V8 version %s\n", v8::V8::GetVersion()); 223 static const int kBufferSize = 256; 224 while (true) { 225 char buffer[kBufferSize]; 226 printf("> "); 227 char* str = fgets(buffer, kBufferSize, stdin); 228 if (str == NULL) break; 229 v8::HandleScope handle_scope; 230 ExecuteString(v8::String::New(str), 231 v8::String::New("(shell)"), 232 true, 233 true); 234 } 235 printf("\n"); 236 } 237 238 239 // Executes a string within the current v8 context. 240 bool ExecuteString(v8::Handle<v8::String> source, 241 v8::Handle<v8::Value> name, 242 bool print_result, 243 bool report_exceptions) { 244 v8::HandleScope handle_scope; 245 v8::TryCatch try_catch; 246 v8::Handle<v8::Script> script = v8::Script::Compile(source, name); 247 if (script.IsEmpty()) { 248 // Print errors that happened during compilation. 249 if (report_exceptions) 250 ReportException(&try_catch); 251 return false; 252 } else { 253 v8::Handle<v8::Value> result = script->Run(); 254 if (result.IsEmpty()) { 255 // Print errors that happened during execution. 256 if (report_exceptions) 257 ReportException(&try_catch); 258 return false; 259 } else { 260 if (print_result && !result->IsUndefined()) { 261 // If all went well and the result wasn't undefined then print 262 // the returned value. 263 v8::String::Utf8Value str(result); 264 const char* cstr = ToCString(str); 265 printf("%s\n", cstr); 266 } 267 return true; 268 } 269 } 270 } 271 272 273 void ReportException(v8::TryCatch* try_catch) { 274 v8::HandleScope handle_scope; 275 v8::String::Utf8Value exception(try_catch->Exception()); 276 const char* exception_string = ToCString(exception); 277 v8::Handle<v8::Message> message = try_catch->Message(); 278 if (message.IsEmpty()) { 279 // V8 didn't provide any extra information about this error; just 280 // print the exception. 281 printf("%s\n", exception_string); 282 } else { 283 // Print (filename):(line number): (message). 284 v8::String::Utf8Value filename(message->GetScriptResourceName()); 285 const char* filename_string = ToCString(filename); 286 int linenum = message->GetLineNumber(); 287 printf("%s:%i: %s\n", filename_string, linenum, exception_string); 288 // Print line of source code. 289 v8::String::Utf8Value sourceline(message->GetSourceLine()); 290 const char* sourceline_string = ToCString(sourceline); 291 printf("%s\n", sourceline_string); 292 // Print wavy underline (GetUnderline is deprecated). 293 int start = message->GetStartColumn(); 294 for (int i = 0; i < start; i++) { 295 printf(" "); 296 } 297 int end = message->GetEndColumn(); 298 for (int i = start; i < end; i++) { 299 printf("^"); 300 } 301 printf("\n"); 302 } 303 } 304