The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / samples / lineprocessor.cc @ f230a1cf

History | View | Annotate | Download (14.3 KB)

1
// Copyright 2012 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

    
30
#ifdef ENABLE_DEBUGGER_SUPPORT
31
#include <v8-debug.h>
32
#endif  // ENABLE_DEBUGGER_SUPPORT
33

    
34
#include <fcntl.h>
35
#include <string.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38

    
39
/**
40
 * This sample program should demonstrate certain aspects of debugging
41
 * standalone V8-based application.
42
 *
43
 * The program reads input stream, processes it line by line and print
44
 * the result to output. The actual processing is done by custom JavaScript
45
 * script. The script is specified with command line parameters.
46
 *
47
 * The main cycle of the program will sequentially read lines from standard
48
 * input, process them and print to standard output until input closes.
49
 * There are 2 possible configuration in regard to main cycle.
50
 *
51
 * 1. The main cycle is on C++ side. Program should be run with
52
 * --main-cycle-in-cpp option. Script must declare a function named
53
 * "ProcessLine". The main cycle in C++ reads lines and calls this function
54
 * for processing every time. This is a sample script:
55

56
function ProcessLine(input_line) {
57
  return ">>>" + input_line + "<<<";
58
}
59

60
 *
61
 * 2. The main cycle is in JavaScript. Program should be run with
62
 * --main-cycle-in-js option. Script gets run one time at all and gets
63
 * API of 2 global functions: "read_line" and "print". It should read input
64
 * and print converted lines to output itself. This a sample script:
65

66
while (true) {
67
  var line = read_line();
68
  if (!line) {
69
    break;
70
  }
71
  var res = line + " | " + line;
72
  print(res);
73
}
74

75
 *
76
 * When run with "-p" argument, the program starts V8 Debugger Agent and
77
 * allows remote debugger to attach and debug JavaScript code.
78
 *
79
 * Interesting aspects:
80
 * 1. Wait for remote debugger to attach
81
 * Normally the program compiles custom script and immediately runs it.
82
 * If programmer needs to debug script from the very beginning, he should
83
 * run this sample program with "--wait-for-connection" command line parameter.
84
 * This way V8 will suspend on the first statement and wait for
85
 * debugger to attach.
86
 *
87
 * 2. Unresponsive V8
88
 * V8 Debugger Agent holds a connection with remote debugger, but it does
89
 * respond only when V8 is running some script. In particular, when this program
90
 * is waiting for input, all requests from debugger get deferred until V8
91
 * is called again. See how "--callback" command-line parameter in this sample
92
 * fixes this issue.
93
 */
94

    
95
enum MainCycleType {
96
  CycleInCpp,
97
  CycleInJs
98
};
99

    
100
const char* ToCString(const v8::String::Utf8Value& value);
101
void ReportException(v8::Isolate* isolate, v8::TryCatch* handler);
102
v8::Handle<v8::String> ReadFile(const char* name);
103
v8::Handle<v8::String> ReadLine();
104

    
105
void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
106
void ReadLine(const v8::FunctionCallbackInfo<v8::Value>& args);
107
bool RunCppCycle(v8::Handle<v8::Script> script,
108
                 v8::Local<v8::Context> context,
109
                 bool report_exceptions);
110

    
111

    
112
#ifdef ENABLE_DEBUGGER_SUPPORT
113
v8::Persistent<v8::Context> debug_message_context;
114

    
115
void DispatchDebugMessages() {
116
  // We are in some random thread. We should already have v8::Locker acquired
117
  // (we requested this when registered this callback). We was called
118
  // because new debug messages arrived; they may have already been processed,
119
  // but we shouldn't worry about this.
120
  //
121
  // All we have to do is to set context and call ProcessDebugMessages.
122
  //
123
  // We should decide which V8 context to use here. This is important for
124
  // "evaluate" command, because it must be executed some context.
125
  // In our sample we have only one context, so there is nothing really to
126
  // think about.
127
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
128
  v8::HandleScope handle_scope(isolate);
129
  v8::Local<v8::Context> context =
130
      v8::Local<v8::Context>::New(isolate, debug_message_context);
131
  v8::Context::Scope scope(context);
132

    
133
  v8::Debug::ProcessDebugMessages();
134
}
135
#endif  // ENABLE_DEBUGGER_SUPPORT
136

    
137

    
138
int RunMain(int argc, char* argv[]) {
139
  v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
140
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
141
  v8::HandleScope handle_scope(isolate);
142

    
143
  v8::Handle<v8::String> script_source;
144
  v8::Handle<v8::Value> script_name;
145
  int script_param_counter = 0;
146

    
147
#ifdef ENABLE_DEBUGGER_SUPPORT
148
  int port_number = -1;
149
  bool wait_for_connection = false;
150
  bool support_callback = false;
151
#endif  // ENABLE_DEBUGGER_SUPPORT
152

    
153
  MainCycleType cycle_type = CycleInCpp;
154

    
155
  for (int i = 1; i < argc; i++) {
156
    const char* str = argv[i];
157
    if (strcmp(str, "-f") == 0) {
158
      // Ignore any -f flags for compatibility with the other stand-
159
      // alone JavaScript engines.
160
      continue;
161
    } else if (strcmp(str, "--main-cycle-in-cpp") == 0) {
162
      cycle_type = CycleInCpp;
163
    } else if (strcmp(str, "--main-cycle-in-js") == 0) {
164
      cycle_type = CycleInJs;
165
#ifdef ENABLE_DEBUGGER_SUPPORT
166
    } else if (strcmp(str, "--callback") == 0) {
167
      support_callback = true;
168
    } else if (strcmp(str, "--wait-for-connection") == 0) {
169
      wait_for_connection = true;
170
    } else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
171
      port_number = atoi(argv[i + 1]);  // NOLINT
172
      i++;
173
#endif  // ENABLE_DEBUGGER_SUPPORT
174
    } else if (strncmp(str, "--", 2) == 0) {
175
      printf("Warning: unknown flag %s.\nTry --help for options\n", str);
176
    } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
177
      script_source = v8::String::New(argv[i + 1]);
178
      script_name = v8::String::New("unnamed");
179
      i++;
180
      script_param_counter++;
181
    } else {
182
      // Use argument as a name of file to load.
183
      script_source = ReadFile(str);
184
      script_name = v8::String::New(str);
185
      if (script_source.IsEmpty()) {
186
        printf("Error reading '%s'\n", str);
187
        return 1;
188
      }
189
      script_param_counter++;
190
    }
191
  }
192

    
193
  if (script_param_counter == 0) {
194
    printf("Script is not specified\n");
195
    return 1;
196
  }
197
  if (script_param_counter != 1) {
198
    printf("Only one script may be specified\n");
199
    return 1;
200
  }
201

    
202
  // Create a template for the global object.
203
  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
204

    
205
  // Bind the global 'print' function to the C++ Print callback.
206
  global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
207

    
208
  if (cycle_type == CycleInJs) {
209
    // Bind the global 'read_line' function to the C++ Print callback.
210
    global->Set(v8::String::New("read_line"),
211
                v8::FunctionTemplate::New(ReadLine));
212
  }
213

    
214
  // Create a new execution environment containing the built-in
215
  // functions
216
  v8::Handle<v8::Context> context = v8::Context::New(isolate, NULL, global);
217
  // Enter the newly created execution environment.
218
  v8::Context::Scope context_scope(context);
219

    
220
#ifdef ENABLE_DEBUGGER_SUPPORT
221
  debug_message_context.Reset(isolate, context);
222

    
223
  v8::Locker locker(isolate);
224

    
225
  if (support_callback) {
226
    v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true);
227
  }
228

    
229
  if (port_number != -1) {
230
    v8::Debug::EnableAgent("lineprocessor", port_number, wait_for_connection);
231
  }
232
#endif  // ENABLE_DEBUGGER_SUPPORT
233

    
234
  bool report_exceptions = true;
235

    
236
  v8::Handle<v8::Script> script;
237
  {
238
    // Compile script in try/catch context.
239
    v8::TryCatch try_catch;
240
    script = v8::Script::Compile(script_source, script_name);
241
    if (script.IsEmpty()) {
242
      // Print errors that happened during compilation.
243
      if (report_exceptions)
244
        ReportException(isolate, &try_catch);
245
      return 1;
246
    }
247
  }
248

    
249
  {
250
    v8::TryCatch try_catch;
251

    
252
    script->Run();
253
    if (try_catch.HasCaught()) {
254
      if (report_exceptions)
255
        ReportException(isolate, &try_catch);
256
      return 1;
257
    }
258
  }
259

    
260
  if (cycle_type == CycleInCpp) {
261
    bool res = RunCppCycle(script,
262
                           isolate->GetCurrentContext(),
263
                           report_exceptions);
264
    return !res;
265
  } else {
266
    // All is already done.
267
  }
268
  return 0;
269
}
270

    
271

    
272
bool RunCppCycle(v8::Handle<v8::Script> script,
273
                 v8::Local<v8::Context> context,
274
                 bool report_exceptions) {
275
  v8::Isolate* isolate = context->GetIsolate();
276
#ifdef ENABLE_DEBUGGER_SUPPORT
277
  v8::Locker lock(isolate);
278
#endif  // ENABLE_DEBUGGER_SUPPORT
279

    
280
  v8::Handle<v8::String> fun_name = v8::String::New("ProcessLine");
281
  v8::Handle<v8::Value> process_val = context->Global()->Get(fun_name);
282

    
283
  // If there is no Process function, or if it is not a function,
284
  // bail out
285
  if (!process_val->IsFunction()) {
286
    printf("Error: Script does not declare 'ProcessLine' global function.\n");
287
    return 1;
288
  }
289

    
290
  // It is a function; cast it to a Function
291
  v8::Handle<v8::Function> process_fun =
292
      v8::Handle<v8::Function>::Cast(process_val);
293

    
294

    
295
  while (!feof(stdin)) {
296
    v8::HandleScope handle_scope(isolate);
297

    
298
    v8::Handle<v8::String> input_line = ReadLine();
299
    if (input_line == v8::Undefined(isolate)) {
300
      continue;
301
    }
302

    
303
    const int argc = 1;
304
    v8::Handle<v8::Value> argv[argc] = { input_line };
305

    
306
    v8::Handle<v8::Value> result;
307
    {
308
      v8::TryCatch try_catch;
309
      result = process_fun->Call(isolate->GetCurrentContext()->Global(),
310
                                 argc, argv);
311
      if (try_catch.HasCaught()) {
312
        if (report_exceptions)
313
          ReportException(isolate, &try_catch);
314
        return false;
315
      }
316
    }
317
    v8::String::Utf8Value str(result);
318
    const char* cstr = ToCString(str);
319
    printf("%s\n", cstr);
320
  }
321

    
322
  return true;
323
}
324

    
325

    
326
int main(int argc, char* argv[]) {
327
  v8::V8::InitializeICU();
328
  int result = RunMain(argc, argv);
329
  v8::V8::Dispose();
330
  return result;
331
}
332

    
333

    
334
// Extracts a C string from a V8 Utf8Value.
335
const char* ToCString(const v8::String::Utf8Value& value) {
336
  return *value ? *value : "<string conversion failed>";
337
}
338

    
339

    
340
// Reads a file into a v8 string.
341
v8::Handle<v8::String> ReadFile(const char* name) {
342
  FILE* file = fopen(name, "rb");
343
  if (file == NULL) return v8::Handle<v8::String>();
344

    
345
  fseek(file, 0, SEEK_END);
346
  int size = ftell(file);
347
  rewind(file);
348

    
349
  char* chars = new char[size + 1];
350
  chars[size] = '\0';
351
  for (int i = 0; i < size;) {
352
    int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
353
    i += read;
354
  }
355
  fclose(file);
356
  v8::Handle<v8::String> result = v8::String::New(chars, size);
357
  delete[] chars;
358
  return result;
359
}
360

    
361

    
362
void ReportException(v8::Isolate* isolate, v8::TryCatch* try_catch) {
363
  v8::HandleScope handle_scope(isolate);
364
  v8::String::Utf8Value exception(try_catch->Exception());
365
  const char* exception_string = ToCString(exception);
366
  v8::Handle<v8::Message> message = try_catch->Message();
367
  if (message.IsEmpty()) {
368
    // V8 didn't provide any extra information about this error; just
369
    // print the exception.
370
    printf("%s\n", exception_string);
371
  } else {
372
    // Print (filename):(line number): (message).
373
    v8::String::Utf8Value filename(message->GetScriptResourceName());
374
    const char* filename_string = ToCString(filename);
375
    int linenum = message->GetLineNumber();
376
    printf("%s:%i: %s\n", filename_string, linenum, exception_string);
377
    // Print line of source code.
378
    v8::String::Utf8Value sourceline(message->GetSourceLine());
379
    const char* sourceline_string = ToCString(sourceline);
380
    printf("%s\n", sourceline_string);
381
    // Print wavy underline (GetUnderline is deprecated).
382
    int start = message->GetStartColumn();
383
    for (int i = 0; i < start; i++) {
384
      printf(" ");
385
    }
386
    int end = message->GetEndColumn();
387
    for (int i = start; i < end; i++) {
388
      printf("^");
389
    }
390
    printf("\n");
391
  }
392
}
393

    
394

    
395
// The callback that is invoked by v8 whenever the JavaScript 'print'
396
// function is called.  Prints its arguments on stdout separated by
397
// spaces and ending with a newline.
398
void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
399
  bool first = true;
400
  for (int i = 0; i < args.Length(); i++) {
401
    v8::HandleScope handle_scope(args.GetIsolate());
402
    if (first) {
403
      first = false;
404
    } else {
405
      printf(" ");
406
    }
407
    v8::String::Utf8Value str(args[i]);
408
    const char* cstr = ToCString(str);
409
    printf("%s", cstr);
410
  }
411
  printf("\n");
412
  fflush(stdout);
413
}
414

    
415

    
416
// The callback that is invoked by v8 whenever the JavaScript 'read_line'
417
// function is called. Reads a string from standard input and returns.
418
void ReadLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
419
  if (args.Length() > 0) {
420
    args.GetIsolate()->ThrowException(v8::String::New("Unexpected arguments"));
421
    return;
422
  }
423
  args.GetReturnValue().Set(ReadLine());
424
}
425

    
426

    
427
v8::Handle<v8::String> ReadLine() {
428
  const int kBufferSize = 1024 + 1;
429
  char buffer[kBufferSize];
430

    
431
  char* res;
432
  {
433
#ifdef ENABLE_DEBUGGER_SUPPORT
434
    v8::Unlocker unlocker(v8::Isolate::GetCurrent());
435
#endif  // ENABLE_DEBUGGER_SUPPORT
436
    res = fgets(buffer, kBufferSize, stdin);
437
  }
438
  if (res == NULL) {
439
    v8::Handle<v8::Primitive> t = v8::Undefined(v8::Isolate::GetCurrent());
440
    return v8::Handle<v8::String>::Cast(t);
441
  }
442
  // Remove newline char
443
  for (char* pos = buffer; *pos != '\0'; pos++) {
444
    if (*pos == '\n') {
445
      *pos = '\0';
446
      break;
447
    }
448
  }
449
  return v8::String::New(buffer);
450
}