mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-11-21 12:18:58 +00:00
Add examples (#475)
This commit is contained in:
parent
1988c98f3c
commit
35dbd2c0ff
@ -60,3 +60,12 @@ which = "4.0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
trybuild = "1.0.33"
|
||||
|
||||
[[example]]
|
||||
name = "hello_world"
|
||||
|
||||
[[example]]
|
||||
name = "shell"
|
||||
|
||||
[[example]]
|
||||
name = "process"
|
||||
|
42
examples/count-hosts.js
Normal file
42
examples/count-hosts.js
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2008 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
function Initialize() { }
|
||||
|
||||
function Process(request) {
|
||||
if (options.verbose) {
|
||||
log("Processing " + request.host + request.path +
|
||||
" from " + request.referrer + "@" + request.userAgent);
|
||||
}
|
||||
if (!output[request.host]) {
|
||||
output[request.host] = 1;
|
||||
} else {
|
||||
output[request.host]++
|
||||
}
|
||||
}
|
||||
|
||||
Initialize();
|
65
examples/hello_world.rs
Normal file
65
examples/hello_world.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use rusty_v8 as v8;
|
||||
|
||||
fn main() {
|
||||
// Initialize V8.
|
||||
let platform = v8::new_default_platform().unwrap();
|
||||
v8::V8::initialize_platform(platform);
|
||||
v8::V8::initialize();
|
||||
|
||||
// Create a new Isolate and make it the current one.
|
||||
let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
|
||||
|
||||
// Create a stack-allocated handle scope.
|
||||
let handle_scope = &mut v8::HandleScope::new(isolate);
|
||||
|
||||
// Create a new context.
|
||||
let context = v8::Context::new(handle_scope);
|
||||
|
||||
// Enter the context for compiling and running the hello world script.
|
||||
let scope = &mut v8::ContextScope::new(handle_scope, context);
|
||||
|
||||
// Create a string containing the JavaScript source code.
|
||||
let code = v8::String::new(scope, "'Hello' + ' World!'").unwrap();
|
||||
|
||||
// Compile the source code.
|
||||
let script = v8::Script::compile(scope, code, None).unwrap();
|
||||
// Run the script to get the result.
|
||||
let result = script.run(scope).unwrap();
|
||||
|
||||
// Convert the result to a string and print it.
|
||||
let result = result.to_string(scope).unwrap();
|
||||
println!("{}", result.to_rust_string_lossy(scope));
|
||||
|
||||
// Use the JavaScript API to generate a WebAssembly module.
|
||||
//
|
||||
// |bytes| contains the binary format for the following module:
|
||||
//
|
||||
// (func (export "add") (param i32 i32) (result i32)
|
||||
// get_local 0
|
||||
// get_local 1
|
||||
// i32.add)
|
||||
//
|
||||
let c_source = r#"
|
||||
let bytes = new Uint8Array([
|
||||
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01,
|
||||
0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07,
|
||||
0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01,
|
||||
0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
|
||||
]);
|
||||
let module = new WebAssembly.Module(bytes);
|
||||
let instance = new WebAssembly.Instance(module);
|
||||
instance.exports.add(3, 4);
|
||||
"#;
|
||||
// Create a string containing the JavaScript source code.
|
||||
let source = v8::String::new(scope, c_source).unwrap();
|
||||
|
||||
// Compile the source code.
|
||||
let script = v8::Script::compile(scope, source, None).unwrap();
|
||||
|
||||
// Run the script to get the result.
|
||||
let result = script.run(scope).unwrap();
|
||||
|
||||
// Print the result.
|
||||
let result = result.to_uint32(scope).unwrap();
|
||||
println!("3 + 4 = {}", result.value());
|
||||
}
|
373
examples/process.rs
Normal file
373
examples/process.rs
Normal file
@ -0,0 +1,373 @@
|
||||
use rusty_v8 as v8;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)] // this function should follow the callback type
|
||||
fn log_callback(
|
||||
scope: &mut v8::HandleScope,
|
||||
args: v8::FunctionCallbackArguments,
|
||||
mut _retval: v8::ReturnValue,
|
||||
) {
|
||||
let message = args
|
||||
.get(0)
|
||||
.to_string(scope)
|
||||
.unwrap()
|
||||
.to_rust_string_lossy(scope);
|
||||
|
||||
println!("Logged: {}", message);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Initialize V8.
|
||||
let platform = v8::new_default_platform().unwrap();
|
||||
v8::V8::initialize_platform(platform);
|
||||
v8::V8::initialize();
|
||||
|
||||
// Parse options.
|
||||
let (options, file) = parse_args();
|
||||
if file.is_empty() {
|
||||
panic!("no script was specified");
|
||||
}
|
||||
|
||||
let mut isolate = v8::Isolate::new(v8::CreateParams::default());
|
||||
let mut scope = v8::HandleScope::new(&mut isolate);
|
||||
|
||||
let source = std::fs::read_to_string(&file)
|
||||
.unwrap_or_else(|err| panic!("failed to open {}: {}", file, err));
|
||||
let source = v8::String::new(&mut scope, &source).unwrap();
|
||||
|
||||
let mut processor = JsHttpRequestProcessor::new(&mut scope, source, options);
|
||||
|
||||
let requests = vec![
|
||||
StringHttpRequest::new("/process.cc", "localhost", "google.com", "firefox"),
|
||||
StringHttpRequest::new("/", "localhost", "google.net", "firefox"),
|
||||
StringHttpRequest::new("/", "localhost", "google.org", "safari"),
|
||||
StringHttpRequest::new("/", "localhost", "yahoo.com", "ie"),
|
||||
StringHttpRequest::new("/", "localhost", "yahoo.com", "safari"),
|
||||
StringHttpRequest::new("/", "localhost", "yahoo.com", "firefox"),
|
||||
];
|
||||
|
||||
for req in requests {
|
||||
processor.process(req);
|
||||
}
|
||||
|
||||
processor.print_output();
|
||||
}
|
||||
|
||||
fn parse_args() -> (HashMap<String, String>, String) {
|
||||
use std::env;
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let mut options = HashMap::new();
|
||||
let mut file = String::new();
|
||||
|
||||
for arg in &args {
|
||||
if let Some(pos) = arg.find('=') {
|
||||
let (key, value) = arg.split_at(pos);
|
||||
let value = &value[1..];
|
||||
options.insert(key.into(), value.into());
|
||||
} else {
|
||||
file = arg.into();
|
||||
}
|
||||
}
|
||||
|
||||
(options, file)
|
||||
}
|
||||
|
||||
/// A simplified HTTP request.
|
||||
trait HttpRequest {
|
||||
fn path(&self) -> &str;
|
||||
fn referrer(&self) -> &str;
|
||||
fn host(&self) -> &str;
|
||||
fn user_agent(&self) -> &str;
|
||||
}
|
||||
|
||||
/// A simplified HTTP request.
|
||||
struct StringHttpRequest {
|
||||
pub path: String,
|
||||
pub referrer: String,
|
||||
pub host: String,
|
||||
pub user_agent: String,
|
||||
}
|
||||
|
||||
impl StringHttpRequest {
|
||||
/// Creates a `StringHttpRequest`.
|
||||
pub fn new(
|
||||
path: impl Into<String>,
|
||||
referrer: impl Into<String>,
|
||||
host: impl Into<String>,
|
||||
user_agent: impl Into<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
path: path.into(),
|
||||
referrer: referrer.into(),
|
||||
host: host.into(),
|
||||
user_agent: user_agent.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HttpRequest for StringHttpRequest {
|
||||
fn path(&self) -> &str {
|
||||
&self.path
|
||||
}
|
||||
|
||||
fn referrer(&self) -> &str {
|
||||
&self.referrer
|
||||
}
|
||||
|
||||
fn host(&self) -> &str {
|
||||
&self.host
|
||||
}
|
||||
|
||||
fn user_agent(&self) -> &str {
|
||||
&self.user_agent
|
||||
}
|
||||
}
|
||||
|
||||
/// An http request processor that is scriptable using JavaScript.
|
||||
struct JsHttpRequestProcessor<'s, 'i> {
|
||||
context: v8::Local<'s, v8::Context>,
|
||||
context_scope: v8::ContextScope<'i, v8::HandleScope<'s>>,
|
||||
process_fn: Option<v8::Local<'s, v8::Function>>,
|
||||
request_template: v8::Global<v8::ObjectTemplate>,
|
||||
_map_template: Option<v8::Global<v8::ObjectTemplate>>,
|
||||
}
|
||||
|
||||
impl<'s, 'i> JsHttpRequestProcessor<'s, 'i>
|
||||
where
|
||||
's: 'i,
|
||||
{
|
||||
/// Creates a scriptable HTTP request processor.
|
||||
pub fn new(
|
||||
isolate_scope: &'i mut v8::HandleScope<'s, ()>,
|
||||
source: v8::Local<'s, v8::String>,
|
||||
options: HashMap<String, String>,
|
||||
) -> Self {
|
||||
let global = v8::ObjectTemplate::new(isolate_scope);
|
||||
global.set(
|
||||
v8::String::new(isolate_scope, "log").unwrap().into(),
|
||||
v8::FunctionTemplate::new(isolate_scope, log_callback).into(),
|
||||
);
|
||||
|
||||
let context = v8::Context::new_from_template(isolate_scope, global);
|
||||
let mut context_scope = v8::ContextScope::new(isolate_scope, context);
|
||||
|
||||
let request_template = v8::ObjectTemplate::new(&mut context_scope);
|
||||
request_template.set_internal_field_count(1);
|
||||
|
||||
// make it global
|
||||
let request_template =
|
||||
v8::Global::new(&mut context_scope, request_template);
|
||||
|
||||
let mut self_ = JsHttpRequestProcessor {
|
||||
context,
|
||||
context_scope,
|
||||
process_fn: None,
|
||||
request_template,
|
||||
_map_template: None,
|
||||
};
|
||||
|
||||
// loads options and output
|
||||
let options = self_.wrap_map(options);
|
||||
let options_str =
|
||||
v8::String::new(&mut self_.context_scope, "options").unwrap();
|
||||
self_.context.global(&mut self_.context_scope).set(
|
||||
&mut self_.context_scope,
|
||||
options_str.into(),
|
||||
options.into(),
|
||||
);
|
||||
|
||||
let output = v8::Object::new(&mut self_.context_scope);
|
||||
let output_str =
|
||||
v8::String::new(&mut self_.context_scope, "output").unwrap();
|
||||
self_.context.global(&mut self_.context_scope).set(
|
||||
&mut self_.context_scope,
|
||||
output_str.into(),
|
||||
output.into(),
|
||||
);
|
||||
|
||||
// execute script
|
||||
self_.execute_script(source);
|
||||
|
||||
let process_str =
|
||||
v8::String::new(&mut self_.context_scope, "Process").unwrap();
|
||||
let process_fn = self_
|
||||
.context
|
||||
.global(&mut self_.context_scope)
|
||||
.get(&mut self_.context_scope, process_str.into())
|
||||
.expect("missing function Process");
|
||||
|
||||
let process_fn = v8::Local::<v8::Function>::try_from(process_fn)
|
||||
.expect("function expected");
|
||||
self_.process_fn = Some(process_fn);
|
||||
|
||||
self_
|
||||
}
|
||||
|
||||
fn execute_script(&mut self, script: v8::Local<'s, v8::String>) {
|
||||
let scope = &mut v8::HandleScope::new(&mut self.context_scope);
|
||||
let try_catch = &mut v8::TryCatch::new(scope);
|
||||
|
||||
let script = v8::Script::compile(try_catch, script, None)
|
||||
.expect("failed to compile script");
|
||||
|
||||
if script.run(try_catch).is_none() {
|
||||
let exception = try_catch.exception().unwrap();
|
||||
let exception_string = exception
|
||||
.to_string(try_catch)
|
||||
.unwrap()
|
||||
.to_rust_string_lossy(try_catch);
|
||||
|
||||
panic!("{}", exception_string);
|
||||
}
|
||||
}
|
||||
|
||||
/// Processes the given HTTP request.
|
||||
pub fn process<R>(&mut self, request: R)
|
||||
where
|
||||
R: HttpRequest + 'static,
|
||||
{
|
||||
let request: Box<dyn HttpRequest> = Box::new(request);
|
||||
let request = self.wrap_request(request);
|
||||
|
||||
let scope = &mut v8::HandleScope::new(&mut self.context_scope);
|
||||
let try_catch = &mut v8::TryCatch::new(scope);
|
||||
|
||||
let process_fn = self.process_fn.as_mut().unwrap();
|
||||
let global = self.context.global(try_catch).into();
|
||||
|
||||
if process_fn
|
||||
.call(try_catch, global, &[request.into()])
|
||||
.is_none()
|
||||
{
|
||||
let exception = try_catch.exception().unwrap();
|
||||
let exception_string = exception
|
||||
.to_string(try_catch)
|
||||
.unwrap()
|
||||
.to_rust_string_lossy(try_catch);
|
||||
|
||||
panic!("{}", exception_string);
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility function that wraps a http request object in a JavaScript object.
|
||||
fn wrap_request(
|
||||
&mut self,
|
||||
request: Box<dyn HttpRequest>,
|
||||
) -> v8::Local<'s, v8::Object> {
|
||||
// TODO: fix memory leak
|
||||
|
||||
use std::ffi::c_void;
|
||||
|
||||
// Dobule-box to get C-sized reference of Box<dyn HttpRequest>
|
||||
let request = Box::new(request);
|
||||
|
||||
// Local scope for temporary handles.
|
||||
let scope = &mut self.context_scope;
|
||||
|
||||
let request_template = v8::Local::new(scope, &self.request_template);
|
||||
let result = request_template.new_instance(scope).unwrap();
|
||||
|
||||
let external = v8::External::new(
|
||||
scope,
|
||||
Box::leak(request) as *mut Box<dyn HttpRequest> as *mut c_void,
|
||||
);
|
||||
|
||||
result.set_internal_field(0, external.into());
|
||||
|
||||
let name = v8::String::new(scope, "path").unwrap().into();
|
||||
result.set_accessor(scope, name, Self::request_prop_handler);
|
||||
let name = v8::String::new(scope, "userAgent").unwrap().into();
|
||||
result.set_accessor(scope, name, Self::request_prop_handler);
|
||||
let name = v8::String::new(scope, "referrer").unwrap().into();
|
||||
result.set_accessor(scope, name, Self::request_prop_handler);
|
||||
let name = v8::String::new(scope, "host").unwrap().into();
|
||||
result.set_accessor(scope, name, Self::request_prop_handler);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// This handles the properties of `HttpRequest`
|
||||
#[allow(clippy::needless_pass_by_value)] // this function should follow the callback type
|
||||
fn request_prop_handler(
|
||||
scope: &mut v8::HandleScope,
|
||||
key: v8::Local<v8::Name>,
|
||||
args: v8::PropertyCallbackArguments,
|
||||
mut rv: v8::ReturnValue,
|
||||
) {
|
||||
let this = args.this();
|
||||
let external = Self::unwrap_request(scope, this);
|
||||
|
||||
assert!(
|
||||
!external.is_null(),
|
||||
"the pointer to Box<dyn HttpRequest> should not be null"
|
||||
);
|
||||
|
||||
let request = unsafe { &mut *external };
|
||||
|
||||
let key = key.to_string(scope).unwrap().to_rust_string_lossy(scope);
|
||||
|
||||
let value = match &*key {
|
||||
"path" => request.path(),
|
||||
"userAgent" => request.user_agent(),
|
||||
"referrer" => request.referrer(),
|
||||
"host" => request.host(),
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
rv.set(v8::String::new(scope, value).unwrap().into());
|
||||
}
|
||||
|
||||
/// Utility function that extracts the http request object from a wrapper object.
|
||||
fn unwrap_request<'a>(
|
||||
scope: &mut v8::HandleScope,
|
||||
request: v8::Local<'a, v8::Object>,
|
||||
) -> *mut Box<dyn HttpRequest> {
|
||||
let external = request.get_internal_field(scope, 0).unwrap();
|
||||
let external = unsafe { v8::Local::<v8::External>::cast(external) };
|
||||
external.value() as *mut Box<dyn HttpRequest>
|
||||
}
|
||||
|
||||
fn wrap_map(
|
||||
&mut self,
|
||||
options: HashMap<String, String>,
|
||||
) -> v8::Local<'s, v8::Object> {
|
||||
// TODO: wrap map, not convert into Object
|
||||
let scope = &mut self.context_scope;
|
||||
let result = v8::Object::new(scope);
|
||||
|
||||
for (key, value) in options {
|
||||
let key = v8::String::new(scope, &key).unwrap().into();
|
||||
let value = v8::String::new(scope, &value).unwrap().into();
|
||||
result.set(scope, key, value);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Prints the output.
|
||||
pub fn print_output(&mut self) {
|
||||
let scope = &mut v8::HandleScope::new(&mut self.context_scope);
|
||||
let key = v8::String::new(scope, "output").unwrap();
|
||||
let output = self
|
||||
.context
|
||||
.global(scope)
|
||||
.get(scope, key.into())
|
||||
.unwrap()
|
||||
.to_object(scope)
|
||||
.unwrap();
|
||||
|
||||
let props = output.get_property_names(scope).unwrap();
|
||||
for i in 0..props.length() {
|
||||
let key = props.get_index(scope, i).unwrap();
|
||||
let value = output.get(scope, key).unwrap();
|
||||
|
||||
let key = key.to_string(scope).unwrap().to_rust_string_lossy(scope);
|
||||
let value = value.to_string(scope).unwrap().to_rust_string_lossy(scope);
|
||||
|
||||
println!("{}: {}", key, value);
|
||||
}
|
||||
}
|
||||
}
|
222
examples/shell.rs
Normal file
222
examples/shell.rs
Normal file
@ -0,0 +1,222 @@
|
||||
use rusty_v8 as v8;
|
||||
|
||||
fn main() {
|
||||
// Initialize V8.
|
||||
let platform = v8::new_default_platform().unwrap();
|
||||
v8::V8::initialize_platform(platform);
|
||||
v8::V8::initialize();
|
||||
|
||||
// Pass command line arguments to V8.
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let args = v8::V8::set_flags_from_command_line(args);
|
||||
|
||||
let mut run_shell_flag = args.len() == 1;
|
||||
let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
|
||||
let handle_scope = &mut v8::HandleScope::new(isolate);
|
||||
|
||||
let context = v8::Context::new(handle_scope);
|
||||
|
||||
let context_scope = &mut v8::ContextScope::new(handle_scope, context);
|
||||
let scope = &mut v8::HandleScope::new(context_scope);
|
||||
|
||||
run_main(scope, &*args, &mut run_shell_flag);
|
||||
|
||||
if run_shell_flag {
|
||||
run_shell(scope);
|
||||
}
|
||||
}
|
||||
|
||||
/// Process remaining command line arguments and execute files
|
||||
fn run_shell(scope: &mut v8::HandleScope) {
|
||||
use std::io::{self, Write};
|
||||
|
||||
println!("V8 version {} [sample shell]", v8::V8::get_version());
|
||||
|
||||
loop {
|
||||
print!("> ");
|
||||
io::stdout().flush().unwrap();
|
||||
|
||||
let mut buf = String::new();
|
||||
match io::stdin().read_line(&mut buf) {
|
||||
Ok(n) => {
|
||||
if n == 0 {
|
||||
println!();
|
||||
return;
|
||||
}
|
||||
|
||||
execute_string(scope, &buf, "(shell)", true, true);
|
||||
}
|
||||
Err(error) => println!("error: {}", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Process remaining command line arguments and execute files
|
||||
fn run_main(
|
||||
scope: &mut v8::HandleScope,
|
||||
args: &[String],
|
||||
run_shell: &mut bool,
|
||||
) {
|
||||
let mut skip_next = false;
|
||||
|
||||
// Parse command-line arguments.
|
||||
for (i, arg) in args.iter().enumerate().skip(1) {
|
||||
if skip_next {
|
||||
continue;
|
||||
}
|
||||
|
||||
match &**arg {
|
||||
"--shell" => {
|
||||
// Enables the shell.
|
||||
*run_shell = true;
|
||||
}
|
||||
"-f" => {
|
||||
// Ignore any -f flags for compatibility with the other stand-
|
||||
// alone JavaScript engines.
|
||||
}
|
||||
"-e" => {
|
||||
// Execute script.
|
||||
let script: &str = &args[i + 1];
|
||||
skip_next = true;
|
||||
|
||||
// TODO: pump event loop (not implemented on rusty_v8?)
|
||||
// while v8::Platform::pump_message_loop(&platform, isolate) {
|
||||
// // do nothing
|
||||
// }
|
||||
execute_string(scope, script, "unnamed", false, true);
|
||||
}
|
||||
arg => {
|
||||
if arg.starts_with("--") {
|
||||
eprintln!("Warning: unknown flag {}.\nTry --help for options", arg);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use all other arguments as names of files to load and run.
|
||||
let script = std::fs::read_to_string(arg).expect("failed to read file");
|
||||
execute_string(scope, &script, arg, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_string(
|
||||
scope: &mut v8::HandleScope,
|
||||
script: &str,
|
||||
filename: &str,
|
||||
print_result: bool,
|
||||
report_exceptions_flag: bool,
|
||||
) {
|
||||
let mut scope = v8::TryCatch::new(scope);
|
||||
|
||||
let script = v8::String::new(&mut scope, script).unwrap();
|
||||
let origin = v8::ScriptOrigin::new(
|
||||
v8::String::new(&mut scope, filename).unwrap().into(),
|
||||
v8::Integer::new(&mut scope, 0),
|
||||
v8::Integer::new(&mut scope, 0),
|
||||
v8::Boolean::new(&mut scope, false),
|
||||
v8::Integer::new(&mut scope, 0),
|
||||
v8::undefined(&mut scope).into(),
|
||||
v8::Boolean::new(&mut scope, false),
|
||||
v8::Boolean::new(&mut scope, false),
|
||||
v8::Boolean::new(&mut scope, false),
|
||||
);
|
||||
|
||||
let script = if let Some(script) =
|
||||
v8::Script::compile(&mut scope, script, Some(&origin))
|
||||
{
|
||||
script
|
||||
} else {
|
||||
assert!(scope.has_caught());
|
||||
|
||||
if report_exceptions_flag {
|
||||
report_exceptions(scope);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(result) = script.run(&mut scope) {
|
||||
if print_result {
|
||||
println!(
|
||||
"{}",
|
||||
result
|
||||
.to_string(&mut scope)
|
||||
.unwrap()
|
||||
.to_rust_string_lossy(&mut scope)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
assert!(scope.has_caught());
|
||||
if report_exceptions_flag {
|
||||
report_exceptions(scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_exceptions(mut try_catch: v8::TryCatch<v8::HandleScope>) {
|
||||
let exception = try_catch.exception().unwrap();
|
||||
let exception_string = exception
|
||||
.to_string(&mut try_catch)
|
||||
.unwrap()
|
||||
.to_rust_string_lossy(&mut try_catch);
|
||||
let message = if let Some(message) = try_catch.message() {
|
||||
message
|
||||
} else {
|
||||
eprintln!("{}", exception_string);
|
||||
return;
|
||||
};
|
||||
|
||||
// Print (filename):(line number): (message).
|
||||
let filename = message
|
||||
.get_script_resource_name(&mut try_catch)
|
||||
.map_or_else(
|
||||
|| "(unknown)".into(),
|
||||
|s| {
|
||||
s.to_string(&mut try_catch)
|
||||
.unwrap()
|
||||
.to_rust_string_lossy(&mut try_catch)
|
||||
},
|
||||
);
|
||||
let line_number = message.get_line_number(&mut try_catch).unwrap_or_default();
|
||||
|
||||
eprintln!("{}:{}: {}", filename, line_number, exception_string);
|
||||
|
||||
// Print line of source code.
|
||||
let source_line = message
|
||||
.get_source_line(&mut try_catch)
|
||||
.map(|s| {
|
||||
s.to_string(&mut try_catch)
|
||||
.unwrap()
|
||||
.to_rust_string_lossy(&mut try_catch)
|
||||
})
|
||||
.unwrap();
|
||||
eprintln!("{}", source_line);
|
||||
|
||||
// Print wavy underline (GetUnderline is deprecated).
|
||||
let start_column = message.get_start_column();
|
||||
let end_column = message.get_end_column();
|
||||
|
||||
for _ in 0..start_column {
|
||||
eprint!(" ");
|
||||
}
|
||||
|
||||
for _ in start_column..end_column {
|
||||
eprint!("^");
|
||||
}
|
||||
|
||||
eprintln!();
|
||||
|
||||
// Print stack trace
|
||||
let stack_trace = if let Some(stack_trace) = try_catch.stack_trace() {
|
||||
stack_trace
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let stack_trace = unsafe { v8::Local::<v8::String>::cast(stack_trace) };
|
||||
let stack_trace = stack_trace
|
||||
.to_string(&mut try_catch)
|
||||
.map(|s| s.to_rust_string_lossy(&mut try_catch));
|
||||
|
||||
if let Some(stack_trace) = stack_trace {
|
||||
eprintln!("{}", stack_trace);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user