blob: da18cc71d3b906a267ae4eed2317da3a8bbc0962 [file] [log] [blame]
jkummerow@chromium.orgd9a13a22012-03-30 14:03:50 +00001// Copyright 2012 the V8 project authors. All rights reserved.
kasper.lund7276f142008-07-30 08:49:36 +00002// 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
ulan@chromium.org57ff8812013-05-10 08:16:55 +000028// TODO(dcarney): remove this
29#define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
30#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
31#define V8_ALLOW_ACCESS_TO_PERSISTENT_ARROW
32
kasper.lund7276f142008-07-30 08:49:36 +000033#include <v8.h>
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000034#include <assert.h>
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000035#include <fcntl.h>
36#include <string.h>
37#include <stdio.h>
38#include <stdlib.h>
kasper.lund7276f142008-07-30 08:49:36 +000039
rossberg@chromium.org28a37082011-08-22 11:03:23 +000040#ifdef COMPRESS_STARTUP_DATA_BZ2
41#error Using compressed startup data is not supported for this sample
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000042#endif
43
rossberg@chromium.org28a37082011-08-22 11:03:23 +000044/**
45 * This sample program shows how to implement a simple javascript shell
46 * based on V8. This includes initializing V8 with command line options,
47 * creating global functions, compiling and executing strings.
48 *
49 * For a more sophisticated shell, consider using the debug shell D8.
50 */
51
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000052
ulan@chromium.org57ff8812013-05-10 08:16:55 +000053v8::Handle<v8::Context> CreateShellContext(v8::Isolate* isolate);
kasper.lund7276f142008-07-30 08:49:36 +000054void RunShell(v8::Handle<v8::Context> context);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000055int RunMain(v8::Isolate* isolate, int argc, char* argv[]);
56bool ExecuteString(v8::Isolate* isolate,
57 v8::Handle<v8::String> source,
mads.s.agercbaa0602008-08-14 13:41:48 +000058 v8::Handle<v8::Value> name,
ager@chromium.org9258b6b2008-09-11 09:11:10 +000059 bool print_result,
60 bool report_exceptions);
kasper.lund7276f142008-07-30 08:49:36 +000061v8::Handle<v8::Value> Print(const v8::Arguments& args);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000062v8::Handle<v8::Value> Read(const v8::Arguments& args);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000063v8::Handle<v8::Value> Load(const v8::Arguments& args);
64v8::Handle<v8::Value> Quit(const v8::Arguments& args);
65v8::Handle<v8::Value> Version(const v8::Arguments& args);
kasper.lund7276f142008-07-30 08:49:36 +000066v8::Handle<v8::String> ReadFile(const char* name);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000067void ReportException(v8::Isolate* isolate, v8::TryCatch* handler);
kasper.lund7276f142008-07-30 08:49:36 +000068
69
rossberg@chromium.org28a37082011-08-22 11:03:23 +000070static bool run_shell;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000071
72
rossberg@chromium.org28a37082011-08-22 11:03:23 +000073int main(int argc, char* argv[]) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000074 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000075 v8::Isolate* isolate = v8::Isolate::GetCurrent();
rossberg@chromium.org28a37082011-08-22 11:03:23 +000076 run_shell = (argc == 1);
jkummerow@chromium.orgd9a13a22012-03-30 14:03:50 +000077 int result;
78 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000079 v8::HandleScope handle_scope(isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000080 v8::Handle<v8::Context> context = CreateShellContext(isolate);
jkummerow@chromium.orgd9a13a22012-03-30 14:03:50 +000081 if (context.IsEmpty()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000082 fprintf(stderr, "Error creating context\n");
jkummerow@chromium.orgd9a13a22012-03-30 14:03:50 +000083 return 1;
84 }
85 context->Enter();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000086 result = RunMain(isolate, argc, argv);
jkummerow@chromium.orgd9a13a22012-03-30 14:03:50 +000087 if (run_shell) RunShell(context);
88 context->Exit();
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000089 }
ager@chromium.org41826e72009-03-30 13:30:57 +000090 v8::V8::Dispose();
91 return result;
92}
93
94
iposva@chromium.org245aa852009-02-10 00:49:54 +000095// Extracts a C string from a V8 Utf8Value.
96const char* ToCString(const v8::String::Utf8Value& value) {
97 return *value ? *value : "<string conversion failed>";
98}
99
100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000101// Creates a new execution environment containing the built-in
102// functions.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000103v8::Handle<v8::Context> CreateShellContext(v8::Isolate* isolate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000104 // Create a template for the global object.
105 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
106 // Bind the global 'print' function to the C++ Print callback.
107 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
108 // Bind the global 'read' function to the C++ Read callback.
109 global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
110 // Bind the global 'load' function to the C++ Load callback.
111 global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
112 // Bind the 'quit' function
113 global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
114 // Bind the 'version' function
115 global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000116
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000117 return v8::Context::New(isolate, NULL, global);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000118}
119
120
kasper.lund7276f142008-07-30 08:49:36 +0000121// The callback that is invoked by v8 whenever the JavaScript 'print'
122// function is called. Prints its arguments on stdout separated by
123// spaces and ending with a newline.
124v8::Handle<v8::Value> Print(const v8::Arguments& args) {
125 bool first = true;
126 for (int i = 0; i < args.Length(); i++) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000127 v8::HandleScope handle_scope(args.GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000128 if (first) {
129 first = false;
130 } else {
131 printf(" ");
132 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000133 v8::String::Utf8Value str(args[i]);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000134 const char* cstr = ToCString(str);
135 printf("%s", cstr);
kasper.lund7276f142008-07-30 08:49:36 +0000136 }
137 printf("\n");
ager@chromium.org41826e72009-03-30 13:30:57 +0000138 fflush(stdout);
kasper.lund7276f142008-07-30 08:49:36 +0000139 return v8::Undefined();
140}
141
142
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000143// The callback that is invoked by v8 whenever the JavaScript 'read'
144// function is called. This function loads the content of the file named in
145// the argument into a JavaScript string.
146v8::Handle<v8::Value> Read(const v8::Arguments& args) {
147 if (args.Length() != 1) {
148 return v8::ThrowException(v8::String::New("Bad parameters"));
149 }
150 v8::String::Utf8Value file(args[0]);
151 if (*file == NULL) {
152 return v8::ThrowException(v8::String::New("Error loading file"));
153 }
154 v8::Handle<v8::String> source = ReadFile(*file);
155 if (source.IsEmpty()) {
156 return v8::ThrowException(v8::String::New("Error loading file"));
157 }
158 return source;
159}
160
161
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000162// The callback that is invoked by v8 whenever the JavaScript 'load'
163// function is called. Loads, compiles and executes its argument
164// JavaScript file.
165v8::Handle<v8::Value> Load(const v8::Arguments& args) {
166 for (int i = 0; i < args.Length(); i++) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000167 v8::HandleScope handle_scope(args.GetIsolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000168 v8::String::Utf8Value file(args[i]);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000169 if (*file == NULL) {
170 return v8::ThrowException(v8::String::New("Error loading file"));
171 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000172 v8::Handle<v8::String> source = ReadFile(*file);
173 if (source.IsEmpty()) {
174 return v8::ThrowException(v8::String::New("Error loading file"));
175 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000176 if (!ExecuteString(args.GetIsolate(),
177 source,
178 v8::String::New(*file),
179 false,
180 false)) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000181 return v8::ThrowException(v8::String::New("Error executing file"));
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000182 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000183 }
184 return v8::Undefined();
185}
186
187
188// The callback that is invoked by v8 whenever the JavaScript 'quit'
189// function is called. Quits.
190v8::Handle<v8::Value> Quit(const v8::Arguments& args) {
191 // If not arguments are given args[0] will yield undefined which
192 // converts to the integer value 0.
193 int exit_code = args[0]->Int32Value();
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000194 fflush(stdout);
195 fflush(stderr);
196 exit(exit_code);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000197 return v8::Undefined();
198}
199
200
201v8::Handle<v8::Value> Version(const v8::Arguments& args) {
202 return v8::String::New(v8::V8::GetVersion());
203}
204
205
kasper.lund7276f142008-07-30 08:49:36 +0000206// Reads a file into a v8 string.
207v8::Handle<v8::String> ReadFile(const char* name) {
208 FILE* file = fopen(name, "rb");
209 if (file == NULL) return v8::Handle<v8::String>();
210
211 fseek(file, 0, SEEK_END);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000212 int size = ftell(file);
kasper.lund7276f142008-07-30 08:49:36 +0000213 rewind(file);
214
215 char* chars = new char[size + 1];
216 chars[size] = '\0';
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000217 for (int i = 0; i < size;) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000218 int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
kasper.lund7276f142008-07-30 08:49:36 +0000219 i += read;
220 }
221 fclose(file);
222 v8::Handle<v8::String> result = v8::String::New(chars, size);
223 delete[] chars;
224 return result;
225}
226
227
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000228// Process remaining command line arguments and execute files
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000229int RunMain(v8::Isolate* isolate, int argc, char* argv[]) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000230 for (int i = 1; i < argc; i++) {
231 const char* str = argv[i];
232 if (strcmp(str, "--shell") == 0) {
233 run_shell = true;
234 } else if (strcmp(str, "-f") == 0) {
235 // Ignore any -f flags for compatibility with the other stand-
236 // alone JavaScript engines.
237 continue;
238 } else if (strncmp(str, "--", 2) == 0) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000239 fprintf(stderr,
240 "Warning: unknown flag %s.\nTry --help for options\n", str);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000241 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
242 // Execute argument given to -e option directly.
243 v8::Handle<v8::String> file_name = v8::String::New("unnamed");
244 v8::Handle<v8::String> source = v8::String::New(argv[++i]);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000245 if (!ExecuteString(isolate, source, file_name, false, true)) return 1;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000246 } else {
247 // Use all other arguments as names of files to load and run.
248 v8::Handle<v8::String> file_name = v8::String::New(str);
249 v8::Handle<v8::String> source = ReadFile(str);
250 if (source.IsEmpty()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000251 fprintf(stderr, "Error reading '%s'\n", str);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000252 continue;
253 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000254 if (!ExecuteString(isolate, source, file_name, false, true)) return 1;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000255 }
256 }
257 return 0;
258}
259
260
kasper.lund7276f142008-07-30 08:49:36 +0000261// The read-eval-execute loop of the shell.
262void RunShell(v8::Handle<v8::Context> context) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000263 fprintf(stderr, "V8 version %s [sample shell]\n", v8::V8::GetVersion());
kasper.lund7276f142008-07-30 08:49:36 +0000264 static const int kBufferSize = 256;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000265 // Enter the execution environment before evaluating any code.
266 v8::Context::Scope context_scope(context);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000267 v8::Local<v8::String> name(v8::String::New("(shell)"));
kasper.lund7276f142008-07-30 08:49:36 +0000268 while (true) {
269 char buffer[kBufferSize];
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000270 fprintf(stderr, "> ");
kasper.lund7276f142008-07-30 08:49:36 +0000271 char* str = fgets(buffer, kBufferSize, stdin);
272 if (str == NULL) break;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000273 v8::HandleScope handle_scope(context->GetIsolate());
274 ExecuteString(context->GetIsolate(),
275 v8::String::New(str),
276 name,
277 true,
278 true);
kasper.lund7276f142008-07-30 08:49:36 +0000279 }
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000280 fprintf(stderr, "\n");
kasper.lund7276f142008-07-30 08:49:36 +0000281}
282
283
284// Executes a string within the current v8 context.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000285bool ExecuteString(v8::Isolate* isolate,
286 v8::Handle<v8::String> source,
mads.s.agercbaa0602008-08-14 13:41:48 +0000287 v8::Handle<v8::Value> name,
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000288 bool print_result,
289 bool report_exceptions) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000290 v8::HandleScope handle_scope(isolate);
kasper.lund7276f142008-07-30 08:49:36 +0000291 v8::TryCatch try_catch;
mads.s.agercbaa0602008-08-14 13:41:48 +0000292 v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
kasper.lund7276f142008-07-30 08:49:36 +0000293 if (script.IsEmpty()) {
294 // Print errors that happened during compilation.
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000295 if (report_exceptions)
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000296 ReportException(isolate, &try_catch);
kasper.lund7276f142008-07-30 08:49:36 +0000297 return false;
298 } else {
299 v8::Handle<v8::Value> result = script->Run();
300 if (result.IsEmpty()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000301 assert(try_catch.HasCaught());
kasper.lund7276f142008-07-30 08:49:36 +0000302 // Print errors that happened during execution.
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000303 if (report_exceptions)
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000304 ReportException(isolate, &try_catch);
kasper.lund7276f142008-07-30 08:49:36 +0000305 return false;
306 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000307 assert(!try_catch.HasCaught());
mads.s.agercbaa0602008-08-14 13:41:48 +0000308 if (print_result && !result->IsUndefined()) {
kasper.lund7276f142008-07-30 08:49:36 +0000309 // If all went well and the result wasn't undefined then print
310 // the returned value.
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000311 v8::String::Utf8Value str(result);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000312 const char* cstr = ToCString(str);
313 printf("%s\n", cstr);
kasper.lund7276f142008-07-30 08:49:36 +0000314 }
315 return true;
316 }
317 }
318}
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000319
320
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000321void ReportException(v8::Isolate* isolate, v8::TryCatch* try_catch) {
322 v8::HandleScope handle_scope(isolate);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000323 v8::String::Utf8Value exception(try_catch->Exception());
iposva@chromium.org245aa852009-02-10 00:49:54 +0000324 const char* exception_string = ToCString(exception);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000325 v8::Handle<v8::Message> message = try_catch->Message();
326 if (message.IsEmpty()) {
327 // V8 didn't provide any extra information about this error; just
328 // print the exception.
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000329 fprintf(stderr, "%s\n", exception_string);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000330 } else {
331 // Print (filename):(line number): (message).
332 v8::String::Utf8Value filename(message->GetScriptResourceName());
iposva@chromium.org245aa852009-02-10 00:49:54 +0000333 const char* filename_string = ToCString(filename);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000334 int linenum = message->GetLineNumber();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000335 fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000336 // Print line of source code.
337 v8::String::Utf8Value sourceline(message->GetSourceLine());
iposva@chromium.org245aa852009-02-10 00:49:54 +0000338 const char* sourceline_string = ToCString(sourceline);
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000339 fprintf(stderr, "%s\n", sourceline_string);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000340 // Print wavy underline (GetUnderline is deprecated).
341 int start = message->GetStartColumn();
342 for (int i = 0; i < start; i++) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000343 fprintf(stderr, " ");
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000344 }
345 int end = message->GetEndColumn();
346 for (int i = start; i < end; i++) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000347 fprintf(stderr, "^");
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000348 }
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000349 fprintf(stderr, "\n");
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000350 v8::String::Utf8Value stack_trace(try_catch->StackTrace());
351 if (stack_trace.length() > 0) {
352 const char* stack_trace_string = ToCString(stack_trace);
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000353 fprintf(stderr, "%s\n", stack_trace_string);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000354 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000355 }
356}