Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add repl #998

Merged
merged 1 commit into from
Nov 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
ry marked this conversation as resolved.
Show resolved Hide resolved

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