| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2008 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 |
| 29 #include "d8.h" |
| 30 #include "debug.h" |
| 31 #include "api.h" |
| 32 #include "natives.h" |
| 33 |
| 34 |
| 35 namespace v8 { |
| 36 |
| 37 |
| 38 const char* Shell::kHistoryFileName = ".d8_history"; |
| 39 const char* Shell::kPrompt = "d8> "; |
| 40 |
| 41 |
| 42 LineEditor *LineEditor::first_ = NULL; |
| 43 |
| 44 |
| 45 LineEditor::LineEditor(Type type, const char* name) |
| 46 : type_(type), |
| 47 name_(name), |
| 48 next_(first_) { |
| 49 first_ = this; |
| 50 } |
| 51 |
| 52 |
| 53 LineEditor* LineEditor::Get() { |
| 54 LineEditor* current = first_; |
| 55 LineEditor* best = current; |
| 56 while (current != NULL) { |
| 57 if (current->type_ > best->type_) |
| 58 best = current; |
| 59 current = current->next_; |
| 60 } |
| 61 return best; |
| 62 } |
| 63 |
| 64 |
| 65 class DumbLineEditor: public LineEditor { |
| 66 public: |
| 67 DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { } |
| 68 virtual i::SmartPointer<char> Prompt(const char* prompt); |
| 69 }; |
| 70 |
| 71 |
| 72 static DumbLineEditor dumb_line_editor; |
| 73 |
| 74 |
| 75 i::SmartPointer<char> DumbLineEditor::Prompt(const char* prompt) { |
| 76 static const int kBufferSize = 256; |
| 77 char buffer[kBufferSize]; |
| 78 printf("%s", prompt); |
| 79 char* str = fgets(buffer, kBufferSize, stdin); |
| 80 return i::SmartPointer<char>(str ? i::OS::StrDup(str) : str); |
| 81 } |
| 82 |
| 83 |
| 84 Shell::CounterMap Shell::counter_map_; |
| 85 Persistent<Context> Shell::utility_context_; |
| 86 Persistent<Context> Shell::evaluation_context_; |
| 87 |
| 88 |
| 89 // Executes a string within the current v8 context. |
| 90 bool Shell::ExecuteString(Handle<String> source, |
| 91 Handle<Value> name, |
| 92 bool print_result, |
| 93 bool report_exceptions) { |
| 94 HandleScope handle_scope; |
| 95 TryCatch try_catch; |
| 96 Handle<Script> script = Script::Compile(source, name); |
| 97 if (script.IsEmpty()) { |
| 98 // Print errors that happened during compilation. |
| 99 if (report_exceptions) |
| 100 ReportException(&try_catch); |
| 101 return false; |
| 102 } else { |
| 103 Handle<Value> result = script->Run(); |
| 104 if (result.IsEmpty()) { |
| 105 // Print errors that happened during execution. |
| 106 if (report_exceptions) |
| 107 ReportException(&try_catch); |
| 108 return false; |
| 109 } else { |
| 110 if (print_result && !result->IsUndefined()) { |
| 111 // If all went well and the result wasn't undefined then print |
| 112 // the returned value. |
| 113 String::Utf8Value str(result); |
| 114 printf("%s\n", *str); |
| 115 } |
| 116 return true; |
| 117 } |
| 118 } |
| 119 } |
| 120 |
| 121 |
| 122 Handle<Value> Shell::Print(const Arguments& args) { |
| 123 bool first = true; |
| 124 for (int i = 0; i < args.Length(); i++) { |
| 125 HandleScope handle_scope; |
| 126 if (first) { |
| 127 first = false; |
| 128 } else { |
| 129 printf(" "); |
| 130 } |
| 131 String::Utf8Value str(args[i]); |
| 132 printf("%s", *str); |
| 133 } |
| 134 printf("\n"); |
| 135 return Undefined(); |
| 136 } |
| 137 |
| 138 |
| 139 Handle<Value> Shell::Load(const Arguments& args) { |
| 140 for (int i = 0; i < args.Length(); i++) { |
| 141 HandleScope handle_scope; |
| 142 String::Utf8Value file(args[i]); |
| 143 Handle<String> source = ReadFile(*file); |
| 144 if (source.IsEmpty()) { |
| 145 return ThrowException(String::New("Error loading file")); |
| 146 } |
| 147 if (!ExecuteString(source, String::New(*file), false, false)) { |
| 148 return ThrowException(String::New("Error executing file")); |
| 149 } |
| 150 } |
| 151 return Undefined(); |
| 152 } |
| 153 |
| 154 |
| 155 Handle<Value> Shell::Quit(const Arguments& args) { |
| 156 int exit_code = args[0]->Int32Value(); |
| 157 OnExit(); |
| 158 exit(exit_code); |
| 159 return Undefined(); |
| 160 } |
| 161 |
| 162 |
| 163 Handle<Value> Shell::Version(const Arguments& args) { |
| 164 return String::New(V8::GetVersion()); |
| 165 } |
| 166 |
| 167 |
| 168 void Shell::ReportException(v8::TryCatch* try_catch) { |
| 169 HandleScope handle_scope; |
| 170 String::Utf8Value exception(try_catch->Exception()); |
| 171 Handle<Message> message = try_catch->Message(); |
| 172 if (message.IsEmpty()) { |
| 173 // V8 didn't provide any extra information about this error; just |
| 174 // print the exception. |
| 175 printf("%s\n", *exception); |
| 176 } else { |
| 177 // Print (filename):(line number): (message). |
| 178 String::Utf8Value filename(message->GetScriptResourceName()); |
| 179 int linenum = message->GetLineNumber(); |
| 180 printf("%s:%i: %s\n", *filename, linenum, *exception); |
| 181 // Print line of source code. |
| 182 String::Utf8Value sourceline(message->GetSourceLine()); |
| 183 printf("%s\n", *sourceline); |
| 184 // Print wavy underline (GetUnderline is deprecated). |
| 185 int start = message->GetStartColumn(); |
| 186 for (int i = 0; i < start; i++) { |
| 187 printf(" "); |
| 188 } |
| 189 int end = message->GetEndColumn(); |
| 190 for (int i = start; i < end; i++) { |
| 191 printf("^"); |
| 192 } |
| 193 printf("\n"); |
| 194 } |
| 195 } |
| 196 |
| 197 |
| 198 Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) { |
| 199 HandleScope handle_scope; |
| 200 Context::Scope context_scope(utility_context_); |
| 201 Handle<Object> global = utility_context_->Global(); |
| 202 Handle<Value> fun = global->Get(String::New("GetCompletions")); |
| 203 static const int kArgc = 3; |
| 204 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full }; |
| 205 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv); |
| 206 return handle_scope.Close(Handle<Array>::Cast(val)); |
| 207 } |
| 208 |
| 209 |
| 210 int* Shell::LookupCounter(const wchar_t* name) { |
| 211 CounterMap::iterator item = counter_map_.find(name); |
| 212 if (item != counter_map_.end()) { |
| 213 Counter* result = (*item).second; |
| 214 return result->GetValuePtr(); |
| 215 } |
| 216 Counter* result = new Counter(name); |
| 217 counter_map_[name] = result; |
| 218 return result->GetValuePtr(); |
| 219 } |
| 220 |
| 221 |
| 222 void Shell::Initialize() { |
| 223 // Set up counters |
| 224 if (i::FLAG_dump_counters) |
| 225 V8::SetCounterFunction(LookupCounter); |
| 226 // Initialize the global objects |
| 227 HandleScope scope; |
| 228 Handle<ObjectTemplate> global_template = ObjectTemplate::New(); |
| 229 global_template->Set(String::New("print"), FunctionTemplate::New(Print)); |
| 230 global_template->Set(String::New("load"), FunctionTemplate::New(Load)); |
| 231 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); |
| 232 global_template->Set(String::New("version"), FunctionTemplate::New(Version)); |
| 233 |
| 234 utility_context_ = Context::New(NULL, global_template); |
| 235 utility_context_->SetSecurityToken(Undefined()); |
| 236 Context::Scope utility_scope(utility_context_); |
| 237 |
| 238 // Install the debugger object in the utility scope |
| 239 i::Debug::Load(); |
| 240 i::JSObject* raw_debug = i::Debug::debug_context()->global(); |
| 241 i::JSGlobalObject* debug = i::JSGlobalObject::cast(raw_debug); |
| 242 debug->set_security_token(i::Heap::undefined_value()); |
| 243 utility_context_->Global()->Set(String::New("$debug"), |
| 244 Utils::ToLocal(&raw_debug)); |
| 245 |
| 246 // Run the d8 shell utility script in the utility context |
| 247 int source_index = i::NativesCollection<i::D8>::GetIndex("d8"); |
| 248 i::Vector<const char> shell_source |
| 249 = i::NativesCollection<i::D8>::GetScriptSource(source_index); |
| 250 i::Vector<const char> shell_source_name |
| 251 = i::NativesCollection<i::D8>::GetScriptName(source_index); |
| 252 Handle<String> source = String::New(shell_source.start(), |
| 253 shell_source.length()); |
| 254 Handle<String> name = String::New(shell_source_name.start(), |
| 255 shell_source_name.length()); |
| 256 Script::Compile(source, name)->Run(); |
| 257 |
| 258 // Create the evaluation context |
| 259 evaluation_context_ = Context::New(NULL, global_template); |
| 260 evaluation_context_->SetSecurityToken(Undefined()); |
| 261 } |
| 262 |
| 263 |
| 264 void Shell::OnExit() { |
| 265 if (i::FLAG_dump_counters) { |
| 266 ::printf("+----------------------------------------+----------+\n"); |
| 267 ::printf("| Name | Value |\n"); |
| 268 ::printf("+----------------------------------------+----------+\n"); |
| 269 for (CounterMap::iterator i = counter_map_.begin(); |
| 270 i != counter_map_.end(); |
| 271 i++) { |
| 272 Counter* counter = (*i).second; |
| 273 ::printf("| %-38ls | %8i |\n", counter->name(), counter->value()); |
| 274 } |
| 275 ::printf("+----------------------------------------+----------+\n"); |
| 276 } |
| 277 } |
| 278 |
| 279 |
| 280 // Reads a file into a v8 string. |
| 281 Handle<String> Shell::ReadFile(const char* name) { |
| 282 FILE* file = i::OS::FOpen(name, "rb"); |
| 283 if (file == NULL) return Handle<String>(); |
| 284 |
| 285 fseek(file, 0, SEEK_END); |
| 286 int size = ftell(file); |
| 287 rewind(file); |
| 288 |
| 289 char* chars = new char[size + 1]; |
| 290 chars[size] = '\0'; |
| 291 for (int i = 0; i < size;) { |
| 292 int read = fread(&chars[i], 1, size - i, file); |
| 293 i += read; |
| 294 } |
| 295 fclose(file); |
| 296 Handle<String> result = String::New(chars, size); |
| 297 delete[] chars; |
| 298 return result; |
| 299 } |
| 300 |
| 301 |
| 302 void Shell::RunShell() { |
| 303 LineEditor* editor = LineEditor::Get(); |
| 304 printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name()); |
| 305 editor->Open(); |
| 306 while (true) { |
| 307 HandleScope handle_scope; |
| 308 i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt); |
| 309 if (input.is_empty()) |
| 310 break; |
| 311 editor->AddHistory(*input); |
| 312 Handle<String> name = String::New("(d8)"); |
| 313 ExecuteString(String::New(*input), name, true, true); |
| 314 } |
| 315 editor->Close(); |
| 316 printf("\n"); |
| 317 } |
| 318 |
| 319 |
| 320 int Shell::Main(int argc, char* argv[]) { |
| 321 i::FlagList::SetFlagsFromCommandLine(&argc, argv, true); |
| 322 Initialize(); |
| 323 bool run_shell = (argc == 1); |
| 324 Context::Scope context_scope(evaluation_context_); |
| 325 for (int i = 1; i < argc; i++) { |
| 326 char* str = argv[i]; |
| 327 HandleScope handle_scope; |
| 328 Handle<String> file_name = v8::String::New(str); |
| 329 Handle<String> source = ReadFile(str); |
| 330 if (source.IsEmpty()) { |
| 331 printf("Error reading '%s'\n", str); |
| 332 return 1; |
| 333 } |
| 334 if (!ExecuteString(source, file_name, false, true)) |
| 335 return 1; |
| 336 } |
| 337 if (run_shell) |
| 338 RunShell(); |
| 339 OnExit(); |
| 340 return 0; |
| 341 } |
| 342 } // v8 |
| 343 |
| 344 |
| 345 int main(int argc, char* argv[]) { |
| 346 return v8::Shell::Main(argc, argv); |
| 347 } |
| OLD | NEW |