Skip to content

Commit

Permalink
Add repl
Browse files Browse the repository at this point in the history
- Running repl from js side.
- Add tests for repl behavior.
- Handle ctrl-C and ctrl-D.
  • Loading branch information
hayd authored and ry committed Nov 5, 2018
1 parent 5e48a68 commit 3f6a7e0
Show file tree
Hide file tree
Showing 13 changed files with 505 additions and 13 deletions.
2 changes: 2 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ main_extern = [
"$rust_build:rand",
"$rust_build:remove_dir_all",
"$rust_build:ring",
"$rust_build:rustyline",
"$rust_build:tempfile",
"$rust_build:tokio",
"$rust_build:tokio_executor",
Expand Down Expand Up @@ -114,6 +115,7 @@ ts_sources = [
"js/remove.ts",
"js/rename.ts",
"js/resources.ts",
"js/repl.ts",
"js/stat.ts",
"js/symlink.ts",
"js/text_encoding.ts",
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ libc = "0.2.43"
log = "0.4.6"
rand = "0.5.5"
remove_dir_all = "0.5.1"
rustyline = "2.1.0"
ring = "0.13.2"
tempfile = "3.0.4"
tokio = "0.1.11"
Expand Down
47 changes: 47 additions & 0 deletions build_extra/rust/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,51 @@ import("rust.gni")
crates = "//third_party/rust_crates"
registry_github = "$crates/registry/src/github.com-1ecc6299db9ec823/"

rust_crate("nix") {
source_root = "$registry_github/nix-0.11.0/src/lib.rs"
extern = [
":cfg_if",
":libc",
":void",
":bitflags",
]
}

rust_crate("rustyline") {
source_root = "$registry_github/rustyline-2.1.0/src/lib.rs"
extern = [
":dirs",
":libc",
":log",
":memchr",
":nix",
":unicode_segmentation",
":unicode_width",
":utf8parse",
":winapi",
]
}

rust_crate("bitflags") {
source_root = "$registry_github/bitflags-1.0.4/src/lib.rs"
}

rust_crate("unicode_segmentation") {
source_root = "$registry_github/unicode-segmentation-1.2.1/src/lib.rs"
}

rust_crate("memchr") {
source_root = "$registry_github/memchr-2.1.0/src/lib.rs"
extern = [
":cfg_if",
":libc",
]
}

rust_crate("utf8parse") {
source_root = "$registry_github/utf8parse-0.1.1/src/lib.rs"
}

rust_crate("libc") {
source_root = "$registry_github/libc-0.2.43/src/lib.rs"
features = [ "use_std" ]
Expand Down Expand Up @@ -127,6 +172,7 @@ rust_crate("winapi") {
"knownfolders",
"ktmtypes",
"libloaderapi",
"limits",
"lsalookup",
"minwinbase",
"minwindef",
Expand Down Expand Up @@ -167,6 +213,7 @@ rust_crate("winapi") {
"winnt",
"winreg",
"winsock2",
"winuser",
"ws2def",
"ws2ipdef",
"ws2tcpip",
Expand Down
13 changes: 7 additions & 6 deletions js/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { libdeno } from "./libdeno";
import { args } from "./deno";
import { sendSync, handleAsyncMsgFromRust } from "./dispatch";
import { promiseErrorExaminer, promiseRejectHandler } from "./promise_util";
import { replLoop } from "./repl";
import { version } from "typescript";

function sendStart(): msg.StartRes {
Expand Down Expand Up @@ -77,13 +78,13 @@ export default function denoMain() {
}
log("args", args);
Object.freeze(args);

const inputFn = args[0];
if (!inputFn) {
console.log("No input script specified.");
os.exit(1);
}

compiler.recompile = startResMsg.recompileFlag();
compiler.run(inputFn, `${cwd}/`);

if (inputFn) {
compiler.run(inputFn, `${cwd}/`);
} else {
replLoop();
}
}
89 changes: 89 additions & 0 deletions js/repl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import * as msg from "gen/msg_generated";
import * as flatbuffers from "./flatbuffers";
import { assert } from "./util";
import * as deno from "./deno";
import { close } from "./files";
import * as dispatch from "./dispatch";
import { exit } from "./os";
import { window } from "./globals";

function startRepl(historyFile: string): number {
const builder = flatbuffers.createBuilder();
const historyFile_ = builder.createString(historyFile);

msg.ReplStart.startReplStart(builder);
msg.ReplStart.addHistoryFile(builder, historyFile_);
const inner = msg.ReplStart.endReplStart(builder);

const baseRes = dispatch.sendSync(builder, msg.Any.ReplStart, inner);
assert(baseRes != null);
assert(msg.Any.ReplStartRes === baseRes!.innerType());
const innerRes = new msg.ReplStartRes();
assert(baseRes!.inner(innerRes) != null);
const rid = innerRes.rid();
return rid;
}

// @internal
export function readline(rid: number, prompt: string): string {
const builder = flatbuffers.createBuilder();
const prompt_ = builder.createString(prompt);
msg.ReplReadline.startReplReadline(builder);
msg.ReplReadline.addRid(builder, rid);
msg.ReplReadline.addPrompt(builder, prompt_);
const inner = msg.ReplReadline.endReplReadline(builder);

// TODO use async?
const baseRes = dispatch.sendSync(builder, msg.Any.ReplReadline, inner);

assert(baseRes != null);
assert(msg.Any.ReplReadlineRes === baseRes!.innerType());
const innerRes = new msg.ReplReadlineRes();
assert(baseRes!.inner(innerRes) != null);
const line = innerRes.line();
assert(line !== null);
return line || "";
}

// @internal
export function replLoop(): void {
window.deno = deno; // FIXME use a new scope (rather than window).

const historyFile = "deno_history.txt";
const prompt = "> ";

const rid = startRepl(historyFile);

let line = "";
while (true) {
try {
line = readline(rid, prompt);
line = line.trim();
} catch (err) {
if (err.message === "EOF") {
break;
}
console.error(err);
exit(1);
}
if (!line) {
continue;
}
if (line === ".exit") {
break;
}
try {
const result = eval.call(window, line); // FIXME use a new scope.
console.log(result);
} catch (err) {
if (err instanceof Error) {
console.error(`${err.constructor.name}: ${err.message}`);
} else {
console.error("Thrown:", err);
}
}
}

close(rid);
}
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extern crate libc;
extern crate rand;
extern crate remove_dir_all;
extern crate ring;
extern crate rustyline;
extern crate tempfile;
extern crate tokio;
extern crate tokio_executor;
Expand Down Expand Up @@ -35,6 +36,7 @@ pub mod msg;
pub mod msg_util;
pub mod ops;
pub mod permissions;
mod repl;
pub mod resources;
pub mod snapshot;
mod tokio_util;
Expand Down
22 changes: 22 additions & 0 deletions src/msg.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ union Any {
Rename,
Readlink,
ReadlinkRes,
ReplStart,
ReplStartRes,
ReplReadline,
ReplReadlineRes,
Resources,
ResourcesRes,
Symlink,
Expand Down Expand Up @@ -273,6 +277,24 @@ table ReadlinkRes {
path: string;
}

table ReplStart {
history_file: string;
// TODO add config
}

table ReplStartRes {
rid: int;
}

table ReplReadline {
rid: int;
prompt: string;
}

table ReplReadlineRes {
line: string;
}

table Resources {}

table Resource {
Expand Down
72 changes: 72 additions & 0 deletions src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use futures::Poll;
use hyper;
use hyper::rt::{Future, Stream};
use remove_dir_all::remove_dir_all;
use repl;
use resources::table_entries;
use std;
use std::fs;
Expand Down Expand Up @@ -96,6 +97,8 @@ pub fn dispatch(
msg::Any::Read => op_read,
msg::Any::Remove => op_remove,
msg::Any::Rename => op_rename,
msg::Any::ReplReadline => op_repl_readline,
msg::Any::ReplStart => op_repl_start,
msg::Any::Resources => op_resources,
msg::Any::SetEnv => op_set_env,
msg::Any::Shutdown => op_shutdown,
Expand Down Expand Up @@ -1086,6 +1089,75 @@ fn op_read_link(
})
}

fn op_repl_start(
state: Arc<IsolateState>,
base: &msg::Base,
data: &'static mut [u8],
) -> Box<Op> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_repl_start().unwrap();
let cmd_id = base.cmd_id();
let history_file = String::from(inner.history_file().unwrap());

debug!("op_repl_start {}", history_file);
let history_path = repl::history_path(&state.dir, &history_file);
let repl = repl::Repl::new(history_path);
let resource = resources::add_repl(repl);

let builder = &mut FlatBufferBuilder::new();
let inner = msg::ReplStartRes::create(
builder,
&msg::ReplStartResArgs { rid: resource.rid },
);
ok_future(serialize_response(
cmd_id,
builder,
msg::BaseArgs {
inner: Some(inner.as_union_value()),
inner_type: msg::Any::ReplStartRes,
..Default::default()
},
))
}

fn op_repl_readline(
_state: Arc<IsolateState>,
base: &msg::Base,
data: &'static mut [u8],
) -> Box<Op> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_repl_readline().unwrap();
let cmd_id = base.cmd_id();
let rid = inner.rid();
let prompt = inner.prompt().unwrap().to_owned();
debug!("op_repl_readline {} {}", rid, prompt);

// Ignore this clippy warning until this issue is addressed:
// https://github.com/rust-lang-nursery/rust-clippy/issues/1684
#[cfg_attr(feature = "cargo-clippy", allow(redundant_closure_call))]
Box::new(futures::future::result((move || {
let line = resources::readline(rid, &prompt)?;

let builder = &mut FlatBufferBuilder::new();
let line_off = builder.create_string(&line);
let inner = msg::ReplReadlineRes::create(
builder,
&msg::ReplReadlineResArgs {
line: Some(line_off),
},
);
Ok(serialize_response(
cmd_id,
builder,
msg::BaseArgs {
inner: Some(inner.as_union_value()),
inner_type: msg::Any::ReplReadlineRes,
..Default::default()
},
))
})()))
}

fn op_truncate(
state: &Arc<IsolateState>,
base: &msg::Base,
Expand Down
Loading

0 comments on commit 3f6a7e0

Please sign in to comment.