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

WIP repl inside deno, initial phase #947

Closed
wants to merge 13 commits into from
Closed
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
1 change: 1 addition & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ main_extern = [
"$rust_build:libc",
"$rust_build:log",
"$rust_build:ring",
"$rust_build:rustyline",
"$rust_build:tempfile",
"$rust_build:rand",
"$rust_build:tokio",
Expand Down
47 changes: 46 additions & 1 deletion 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",
]
}

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("unicode_width") {
source_root = "$registry_github/unicode-width-0.1.5/src/lib.rs"
}

rust_crate("libc") {
source_root = "$registry_github/libc-0.2.43/src/lib.rs"
features = [ "use_std" ]
Expand Down Expand Up @@ -659,7 +704,7 @@ rust_crate("hyper_rustls") {
}

rust_crate("dirs") {
source_root = "$registry_github/dirs-1.0.3/src/lib.rs"
source_root = "$registry_github/dirs-1.0.4/src/lib.rs"
extern = [
":libc",
":winapi",
Expand Down
23 changes: 16 additions & 7 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 { repl_loop } from "./repl";

function sendStart(): msg.StartRes {
const builder = new flatbuffers.Builder();
Expand All @@ -33,7 +34,12 @@ function onGlobalError(
} else {
console.log(`Thrown: ${String(error)}`);
}
os.exit(1);
// FIXME this is a hack, and anyway doesn't work for `throw "error"`
// which (for some reason) has source == undefined
if (source !== "deno repl") {
console.log(`Source: ${source}`);
os.exit(1);
}
}

/* tslint:disable-next-line:no-default-export */
Expand Down Expand Up @@ -68,21 +74,24 @@ 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);
// repl!!
// console.log("No input script specified.");
// os.exit(1);
}

// handle `--deps`
if (startResMsg.depsFlag()) {
if (inputFn && startResMsg.depsFlag()) {
for (const dep of compiler.getModuleDependencies(inputFn, `${cwd}/`)) {
console.log(dep);
}
os.exit(0);
}

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

// FIXME assignis like this is bad
window.deno = deno;
/** Read the next line for the repl.
*
* import { readFile } from "deno";
* const decoder = new TextDecoder("utf-8");
* const data = await readFile("hello.txt");
* console.log(decoder.decode(data));
*/
async function readline(prompt: string): Promise<string> {
return res(await dispatch.sendAsync(...req(prompt)));
}

function req(
prompt: string
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
const builder = new flatbuffers.Builder();
const prompt_ = builder.createString(prompt);
msg.Repl.startRepl(builder);
msg.Repl.addPrompt(builder, prompt_);
const inner = msg.Repl.endRepl(builder);
return [builder, msg.Any.Repl, inner];
}

function res(baseRes: null | msg.Base): string {
assert(baseRes != null);
assert(msg.Any.ReplRes === baseRes!.innerType());
const inner = new msg.ReplRes();
assert(baseRes!.inner(inner) != null);
const line = inner.line();
assert(line !== null);
return line ? line : "FIXME"; // FIXME null handling
}

export async function repl_loop() {
while (true) {
const line = await readline(">> ");
try {
const result = eval.call(window, line);
if (result) {
console.log(result);
}
} catch (err) {
console.log(err);
}
}
}
12 changes: 7 additions & 5 deletions src/isolate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use libdeno;

use futures::Future;
use libc::c_void;
use rustyline::Editor;
use std;
use std::ffi::CStr;
use std::ffi::CString;
Expand Down Expand Up @@ -56,6 +57,7 @@ pub struct IsolateState {
pub flags: flags::DenoFlags,
tx: Mutex<Option<mpsc::Sender<(i32, Buf)>>>,
pub metrics: Mutex<Metrics>,
pub repl: Mutex<Option<Editor<()>>>,
}

impl IsolateState {
Expand Down Expand Up @@ -120,6 +122,7 @@ impl Isolate {
flags,
tx: Mutex::new(Some(tx)),
metrics: Mutex::new(Metrics::default()),
repl: Mutex::new(None),
}),
}
}
Expand Down Expand Up @@ -303,11 +306,10 @@ extern "C" fn pre_dispatch(
// manually.
isolate.ntasks_increment();

let task = op
.and_then(move |buf| {
state.send_to_js(req_id, buf);
Ok(())
}).map_err(|_| ());
let task = op.and_then(move |buf| {
state.send_to_js(req_id, buf);
Ok(())
}).map_err(|_| ());
tokio::spawn(task);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
extern crate flatbuffers;
#[macro_use]
extern crate futures;
// extern crate rustyline;
extern crate hyper;
extern crate libc;
extern crate msg_rs as msg;
extern crate rand;
extern crate rustyline;
extern crate tempfile;
extern crate tokio;
extern crate tokio_executor;
Expand All @@ -30,6 +32,7 @@ mod http_util;
mod isolate;
mod libdeno;
pub mod ops;
mod repl;
mod resources;
mod tokio_util;
mod version;
Expand Down Expand Up @@ -78,5 +81,9 @@ fn main() {
std::process::exit(1);
});
isolate.event_loop();
// if no args then enter repl
// if isolate.state.argv.len() == 1 {
// repl::repl_loop(&mut isolate)
// }
});
}
10 changes: 10 additions & 0 deletions src/msg.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ union Any {
Rename,
Readlink,
ReadlinkRes,
Repl,
ReplRes,
Symlink,
Stat,
StatRes,
Expand Down Expand Up @@ -248,6 +250,14 @@ table ReadlinkRes {
path: string;
}

table Repl {
prompt: string;
}

table ReplRes {
line: string;
}

table Symlink {
oldname: string;
newname: string;
Expand Down
38 changes: 38 additions & 0 deletions src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use isolate::Isolate;
use isolate::IsolateState;
use isolate::Op;
use msg;
use repl;
use resources;
use resources::Resource;
use tokio_util;
Expand Down Expand Up @@ -91,6 +92,7 @@ pub fn dispatch(
msg::Any::ReadDir => op_read_dir,
msg::Any::Rename => op_rename,
msg::Any::Readlink => op_read_link,
msg::Any::Repl => op_repl,
msg::Any::Symlink => op_symlink,
msg::Any::SetEnv => op_set_env,
msg::Any::Stat => op_stat,
Expand Down Expand Up @@ -1063,6 +1065,42 @@ fn op_read_link(
})
}

fn op_repl(
state: Arc<IsolateState>, // FIXME (this will be needed!)
base: &msg::Base,
data: &'static mut [u8],
) -> Box<Op> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_repl().unwrap();
let cmd_id = base.cmd_id();
let prompt = inner.prompt().unwrap().to_owned();
// let f = || repl::readline(state, prompt);

blocking!(base.sync(), || -> OpResult {
// debug!("op_repl {}", prompt);
let line = repl::readline(&state, &prompt)?; // FIXME
// let line = f()?;
let builder = &mut FlatBufferBuilder::new();
let line_off = builder.create_string(&line);
let inner = msg::ReplRes::create(
builder,
&msg::ReplResArgs {
line: Some(line_off),
..Default::default()
},
);
Ok(serialize_response(
cmd_id,
builder,
msg::BaseArgs {
inner: Some(inner.as_union_value()),
inner_type: msg::Any::ReplRes,
..Default::default()
},
))
})
}

fn op_truncate(
state: Arc<IsolateState>,
base: &msg::Base,
Expand Down
39 changes: 39 additions & 0 deletions src/repl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
extern crate rustyline;
use rustyline::Editor;

use std::error::Error;
use std::sync::Arc;
//use futures::Future;
use msg::ErrorKind;

use errors::new as deno_error;
use errors::DenoResult;
use isolate;

pub fn readline(
_state: &Arc<isolate::IsolateState>,
prompt: &String,
) -> DenoResult<String> {
// FIXME
// let mut maybe_editor = state.repl.lock().unwrap();
// if maybe_editor.is_none() {
// println!("{}", "Creating new Editor<()>");
// *maybe_editor = Some(start_repl()); // will this assign within IsolateState?
// }
let maybe_editor = Some(start_repl());
maybe_editor
.unwrap()
.readline(prompt)
.map_err(|err| deno_error(ErrorKind::Other, err.description().to_string()))
}

// FIXME can we call save_history when this is dropped / upon exit?
// rl.save_history("history.txt").unwrap();
fn start_repl() -> Editor<()> {
let mut editor = Editor::<()>::new();
if editor.load_history("history.txt").is_err() {
eprintln!("No previous history.");
}
editor
}
2 changes: 1 addition & 1 deletion third_party
Submodule third_party updated 221 files