Skip to content

Commit

Permalink
support repl (#693)
Browse files Browse the repository at this point in the history
* support repl

* fix ci test
  • Loading branch information
ahaoboy authored Nov 22, 2024
1 parent f280bce commit aa742eb
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 7 deletions.
7 changes: 1 addition & 6 deletions llrt/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,7 @@ async fn start_cli(vm: &Vm) {
}
}
} else {
let index = if let Ok(dir) = std::env::current_dir() {
[dir.to_string_lossy().as_ref(), "/index"].concat()
} else {
"index".into()
};
vm.run_file(index, true, false).await;
vm.run_repl().await;
}
}

Expand Down
1 change: 1 addition & 0 deletions llrt_core/src/modules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ pub use llrt_modules::{
pub mod console;
pub mod llrt;
pub mod module;
pub mod repl;
pub mod util;
67 changes: 67 additions & 0 deletions llrt_core/src/modules/repl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use llrt_modules::VERSION;
use llrt_utils::error::ErrorExtensions;
use rquickjs::{prelude::Rest, AsyncContext, CatchResultExt, Ctx, Result, Value};

use crate::modules::console::{self};

fn process_input(ctx: &Ctx<'_>, input: &str) -> String {
match ctx
.eval::<Value, _>(input.as_bytes())
.map(|v| console::format(ctx, Rest(vec![v])).expect("Failed to format"))
.catch(ctx)
{
Ok(s) => s,
Err(caught_err) => {
match caught_err
.into_value(ctx)
.map(|v| console::format(ctx, Rest(vec![v])).expect("Failed to format"))
{
Ok(s) => s,
Err(caught_err) => format!("Error: {:?}", caught_err),
}
},
}
}

pub(crate) async fn run_repl(ctx: &AsyncContext) {
ctx.with(|ctx| -> Result<()> {
let mut input = String::new();
println!("Welcome to llrt v{}", VERSION);
loop {
print!("> ");
std::io::Write::flush(&mut std::io::stdout())?;
std::io::stdin().read_line(&mut input)?;
println!("{}", process_input(&ctx, &input));
input.clear();
}
})
.await
.expect("Failed to run REPL")
}

#[cfg(test)]
mod tests {
use crate::modules::repl::process_input;
use llrt_test::test_sync_with;
use std::io::{stdout, IsTerminal};

#[tokio::test]
async fn test_process_input() {
test_sync_with(|ctx| {
let output = process_input(&ctx, "1+1");
let is_tty = stdout().is_terminal();
let expect = if is_tty { "\u{1b}[33m2\u{1b}[0m" } else { "2" };
assert_eq!(output, expect);

let output = process_input(&ctx, "a");
let expect = if is_tty {
"ReferenceError: a is not defined\u{1b}[30m\n at <eval> (eval_script:1:1)\u{1b}[0m"
} else {
"ReferenceError: a is not defined\n at <eval> (eval_script:1:1)"
};
assert_eq!(output, expect);
Ok(())
})
.await;
}
}
7 changes: 6 additions & 1 deletion llrt_core/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use crate::{
resolver::{require_resolve, CustomResolver},
CJS_IMPORT_PREFIX,
},
modules::{console, crypto::SYSTEM_RANDOM},
modules::{console, crypto::SYSTEM_RANDOM, repl::run_repl},
security,
utils::clone::structured_clone,
};
Expand Down Expand Up @@ -189,6 +189,11 @@ impl Vm {

self.run(source, strict, global).await;
}

pub async fn run_repl(&self) {
run_repl(&self.ctx).await;
}

pub async fn run<S: Into<Vec<u8>> + Send>(&self, source: S, strict: bool, global: bool) {
self.run_with(|ctx| {
let mut options = EvalOptions::default();
Expand Down

0 comments on commit aa742eb

Please sign in to comment.