00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "d8.h"
00030 #include "debug.h"
00031 #include "api.h"
00032 #include "natives.h"
00033
00034
00035 namespace v8 {
00036
00037
00038 const char* Shell::kHistoryFileName = ".d8_history";
00039 const char* Shell::kPrompt = "d8> ";
00040
00041
00042 LineEditor *LineEditor::first_ = NULL;
00043
00044
00045 LineEditor::LineEditor(Type type, const char* name)
00046 : type_(type),
00047 name_(name),
00048 next_(first_) {
00049 first_ = this;
00050 }
00051
00052
00053 LineEditor* LineEditor::Get() {
00054 LineEditor* current = first_;
00055 LineEditor* best = current;
00056 while (current != NULL) {
00057 if (current->type_ > best->type_)
00058 best = current;
00059 current = current->next_;
00060 }
00061 return best;
00062 }
00063
00064
00065 class DumbLineEditor: public LineEditor {
00066 public:
00067 DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
00068 virtual i::SmartPointer<char> Prompt(const char* prompt);
00069 };
00070
00071
00072 static DumbLineEditor dumb_line_editor;
00073
00074
00075 i::SmartPointer<char> DumbLineEditor::Prompt(const char* prompt) {
00076 static const int kBufferSize = 256;
00077 char buffer[kBufferSize];
00078 printf("%s", prompt);
00079 char* str = fgets(buffer, kBufferSize, stdin);
00080 return i::SmartPointer<char>(str ? i::OS::StrDup(str) : str);
00081 }
00082
00083
00084 Shell::CounterMap Shell::counter_map_;
00085 Persistent<Context> Shell::utility_context_;
00086 Persistent<Context> Shell::evaluation_context_;
00087
00088
00089
00090 bool Shell::ExecuteString(Handle<String> source,
00091 Handle<Value> name,
00092 bool print_result,
00093 bool report_exceptions) {
00094 HandleScope handle_scope;
00095 TryCatch try_catch;
00096 Handle<Script> script = Script::Compile(source, name);
00097 if (script.IsEmpty()) {
00098
00099 if (report_exceptions)
00100 ReportException(&try_catch);
00101 return false;
00102 } else {
00103 Handle<Value> result = script->Run();
00104 if (result.IsEmpty()) {
00105
00106 if (report_exceptions)
00107 ReportException(&try_catch);
00108 return false;
00109 } else {
00110 if (print_result && !result->IsUndefined()) {
00111
00112
00113 String::Utf8Value str(result);
00114 printf("%s\n", *str);
00115 }
00116 return true;
00117 }
00118 }
00119 }
00120
00121
00122 Handle<Value> Shell::Print(const Arguments& args) {
00123 bool first = true;
00124 for (int i = 0; i < args.Length(); i++) {
00125 HandleScope handle_scope;
00126 if (first) {
00127 first = false;
00128 } else {
00129 printf(" ");
00130 }
00131 String::Utf8Value str(args[i]);
00132 printf("%s", *str);
00133 }
00134 printf("\n");
00135 return Undefined();
00136 }
00137
00138
00139 Handle<Value> Shell::Load(const Arguments& args) {
00140 for (int i = 0; i < args.Length(); i++) {
00141 HandleScope handle_scope;
00142 String::Utf8Value file(args[i]);
00143 Handle<String> source = ReadFile(*file);
00144 if (source.IsEmpty()) {
00145 return ThrowException(String::New("Error loading file"));
00146 }
00147 if (!ExecuteString(source, String::New(*file), false, false)) {
00148 return ThrowException(String::New("Error executing file"));
00149 }
00150 }
00151 return Undefined();
00152 }
00153
00154
00155 Handle<Value> Shell::Quit(const Arguments& args) {
00156 int exit_code = args[0]->Int32Value();
00157 OnExit();
00158 exit(exit_code);
00159 return Undefined();
00160 }
00161
00162
00163 Handle<Value> Shell::Version(const Arguments& args) {
00164 return String::New(V8::GetVersion());
00165 }
00166
00167
00168 void Shell::ReportException(v8::TryCatch* try_catch) {
00169 HandleScope handle_scope;
00170 String::Utf8Value exception(try_catch->Exception());
00171 Handle<Message> message = try_catch->Message();
00172 if (message.IsEmpty()) {
00173
00174
00175 printf("%s\n", *exception);
00176 } else {
00177
00178 String::Utf8Value filename(message->GetScriptResourceName());
00179 int linenum = message->GetLineNumber();
00180 printf("%s:%i: %s\n", *filename, linenum, *exception);
00181
00182 String::Utf8Value sourceline(message->GetSourceLine());
00183 printf("%s\n", *sourceline);
00184
00185 int start = message->GetStartColumn();
00186 for (int i = 0; i < start; i++) {
00187 printf(" ");
00188 }
00189 int end = message->GetEndColumn();
00190 for (int i = start; i < end; i++) {
00191 printf("^");
00192 }
00193 printf("\n");
00194 }
00195 }
00196
00197
00198 Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
00199 HandleScope handle_scope;
00200 Context::Scope context_scope(utility_context_);
00201 Handle<Object> global = utility_context_->Global();
00202 Handle<Value> fun = global->Get(String::New("GetCompletions"));
00203 static const int kArgc = 3;
00204 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
00205 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
00206 return handle_scope.Close(Handle<Array>::Cast(val));
00207 }
00208
00209
00210 int* Shell::LookupCounter(const wchar_t* name) {
00211 CounterMap::iterator item = counter_map_.find(name);
00212 if (item != counter_map_.end()) {
00213 Counter* result = (*item).second;
00214 return result->GetValuePtr();
00215 }
00216 Counter* result = new Counter(name);
00217 counter_map_[name] = result;
00218 return result->GetValuePtr();
00219 }
00220
00221
00222 void Shell::Initialize() {
00223
00224 if (i::FLAG_dump_counters)
00225 V8::SetCounterFunction(LookupCounter);
00226
00227 HandleScope scope;
00228 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
00229 global_template->Set(String::New("print"), FunctionTemplate::New(Print));
00230 global_template->Set(String::New("load"), FunctionTemplate::New(Load));
00231 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
00232 global_template->Set(String::New("version"), FunctionTemplate::New(Version));
00233
00234 utility_context_ = Context::New(NULL, global_template);
00235 utility_context_->SetSecurityToken(Undefined());
00236 Context::Scope utility_scope(utility_context_);
00237
00238
00239 i::Debug::Load();
00240 i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
00241 i::JSObject* debug = i::Debug::debug_context()->global();
00242 utility_context_->Global()->Set(String::New("$debug"),
00243 Utils::ToLocal(&debug));
00244
00245
00246 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
00247 i::Vector<const char> shell_source
00248 = i::NativesCollection<i::D8>::GetScriptSource(source_index);
00249 i::Vector<const char> shell_source_name
00250 = i::NativesCollection<i::D8>::GetScriptName(source_index);
00251 Handle<String> source = String::New(shell_source.start(),
00252 shell_source.length());
00253 Handle<String> name = String::New(shell_source_name.start(),
00254 shell_source_name.length());
00255 Script::Compile(source, name)->Run();
00256
00257
00258 evaluation_context_ = Context::New(NULL, global_template);
00259 evaluation_context_->SetSecurityToken(Undefined());
00260 }
00261
00262
00263 void Shell::OnExit() {
00264 if (i::FLAG_dump_counters) {
00265 ::printf("+----------------------------------------+----------+\n");
00266 ::printf("| Name | Value |\n");
00267 ::printf("+----------------------------------------+----------+\n");
00268 for (CounterMap::iterator i = counter_map_.begin();
00269 i != counter_map_.end();
00270 i++) {
00271 Counter* counter = (*i).second;
00272 ::printf("| %-38ls | %8i |\n", counter->name(), counter->value());
00273 }
00274 ::printf("+----------------------------------------+----------+\n");
00275 }
00276 }
00277
00278
00279
00280 Handle<String> Shell::ReadFile(const char* name) {
00281 FILE* file = i::OS::FOpen(name, "rb");
00282 if (file == NULL) return Handle<String>();
00283
00284 fseek(file, 0, SEEK_END);
00285 int size = ftell(file);
00286 rewind(file);
00287
00288 char* chars = new char[size + 1];
00289 chars[size] = '\0';
00290 for (int i = 0; i < size;) {
00291 int read = fread(&chars[i], 1, size - i, file);
00292 i += read;
00293 }
00294 fclose(file);
00295 Handle<String> result = String::New(chars, size);
00296 delete[] chars;
00297 return result;
00298 }
00299
00300
00301 void Shell::RunShell() {
00302 LineEditor* editor = LineEditor::Get();
00303 printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
00304 editor->Open();
00305 while (true) {
00306 HandleScope handle_scope;
00307 i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
00308 if (input.is_empty())
00309 break;
00310 editor->AddHistory(*input);
00311 Handle<String> name = String::New("(d8)");
00312 ExecuteString(String::New(*input), name, true, true);
00313 }
00314 editor->Close();
00315 printf("\n");
00316 }
00317
00318
00319 int Shell::Main(int argc, char* argv[]) {
00320 i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
00321 Initialize();
00322 bool run_shell = (argc == 1);
00323 Context::Scope context_scope(evaluation_context_);
00324 for (int i = 1; i < argc; i++) {
00325 char* str = argv[i];
00326 HandleScope handle_scope;
00327 Handle<String> file_name = v8::String::New(str);
00328 Handle<String> source = ReadFile(str);
00329 if (source.IsEmpty()) {
00330 printf("Error reading '%s'\n", str);
00331 return 1;
00332 }
00333 if (!ExecuteString(source, file_name, false, true))
00334 return 1;
00335 }
00336 if (run_shell)
00337 RunShell();
00338 OnExit();
00339 return 0;
00340 }
00341
00342
00343 }
00344
00345
00346 int main(int argc, char* argv[]) {
00347 return v8::Shell::Main(argc, argv);
00348 }