Skip to content

Commit

Permalink
test: add repl test && add config & some debug cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
Chronostasys committed May 13, 2024
1 parent 6cf37e8 commit 59d1d22
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 58 deletions.
2 changes: 1 addition & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ ignore:
- "src/lsp/lspserver.rs"
- "src/lsp/wasm.rs"
- "src/lsp/wasm.rs"
- "src/repl/*.rs"
- "src/repl/editor.rs"
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ fn main() {
RunCommand::Version => cli.version(),
RunCommand::Repl => {
#[cfg(feature = "repl")]
repl::start_repl();
repl::start_repl(repl::editor::default_editor());
#[cfg(not(feature = "repl"))]
eprintln!("feature repl is not enabled, cannot use repl command");
}
Expand Down
62 changes: 62 additions & 0 deletions src/repl/editor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::path::Path;

use rustyline::error::ReadlineError;

use super::completer::REPLCompleter;

pub trait TermEditor {
fn set_helper(&mut self, helper: Option<REPLCompleter>);
fn readline(&mut self, prompt: &str) -> Result<String, ReadlineError>;
/// Load the history from the specified file.
fn load_history<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<(), ReadlineError>;

/// Save the history in the specified file.
fn save_history<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<(), ReadlineError>;

/// Append new entries in the specified file.
fn append_history<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<(), ReadlineError>;

/// Add a new entry in the history.
fn add_history_entry<S: AsRef<str> + Into<String>>(
&mut self,
line: S,
) -> Result<bool, ReadlineError>;

#[cfg(test)]
fn assert_err(&mut self, _err: bool) {
// noop
}
}

pub fn default_editor() -> rustyline::Editor<REPLCompleter, rustyline::history::FileHistory> {
rustyline::Editor::<REPLCompleter, rustyline::history::FileHistory>::new().unwrap()
}

impl TermEditor for rustyline::Editor<REPLCompleter, rustyline::history::FileHistory> {
fn set_helper(&mut self, helper: Option<REPLCompleter>) {
self.set_helper(helper);
}

fn readline(&mut self, prompt: &str) -> Result<String, ReadlineError> {
self.readline(prompt)
}

fn load_history<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<(), ReadlineError> {
self.load_history(path)
}

fn save_history<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<(), ReadlineError> {
self.save_history(path)
}

fn append_history<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<(), ReadlineError> {
self.append_history(path)
}

fn add_history_entry<S: AsRef<str> + Into<String>>(
&mut self,
line: S,
) -> Result<bool, ReadlineError> {
self.add_history_entry(line)
}
}
180 changes: 124 additions & 56 deletions src/repl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use nom::combinator::{eof, map};
use nom::sequence::terminated;
use notify::{Event, EventKind, RecursiveMode, Watcher};
use rustc_hash::{FxHashMap, FxHashSet};
use rustyline::config::Configurer;
use rustyline::error::ReadlineError;
use ustr::{ustr, Ustr};

Expand Down Expand Up @@ -50,7 +49,9 @@ lazy_static::lazy_static! {
pub static ref LOADED_SET:Arc<Mutex<FxHashSet<PathBuf>>> = Arc::new(Mutex::new(FxHashSet::default()));
}

pub fn start_repl() {
pub mod editor;

pub fn start_repl<E: editor::TermEditor>(mut rl: E) {
let mut db = Database::default();
let mut db2 = Database::default();

Expand Down Expand Up @@ -130,10 +131,9 @@ project = "repl"

// `()` can be used when no completer is required
let completer = REPLCompleter::new(&mut db2 as _, mem_check);
let mut rl =
rustyline::Editor::<REPLCompleter, rustyline::history::FileHistory>::new().unwrap();
// let mut rl =
// rustyline::Editor::<REPLCompleter, rustyline::history::FileHistory>::new().unwrap();
rl.set_helper(Some(completer));
rl.set_completion_type(rustyline::CompletionType::Circular);
let _ = rl.load_history(&PathBuf::from(&root).join("history.txt"));

loop {
Expand All @@ -151,6 +151,13 @@ project = "repl"
if try_parse_commands(&line)
.map(|repl| match repl.command {
repl_cmd::Commands::Load { proj_path, _as } => {
let proj_path = match crate::utils::canonicalize(proj_path) {
Ok(p) => p,
Err(e) => {
eprintln!("Error: {:?}", e);
return;
}
};
if let ControlFlow::Break(_) =
validate_proj_cfg(&proj_path, &db2, &docs2)
{
Expand All @@ -170,6 +177,13 @@ project = "repl"
);
}
repl_cmd::Commands::LoadDeps { proj_path } => {
let proj_path = match crate::utils::canonicalize(proj_path) {
Ok(p) => p,
Err(e) => {
eprintln!("Error: {:?}", e);
return;
}
};
match validate_proj_cfg(&proj_path, &db2, &docs2) {
ControlFlow::Continue(cfg) => {
for (as_name, path) in &cfg.deps.unwrap_or_default() {
Expand All @@ -181,14 +195,57 @@ project = "repl"
}
repl_cmd::Commands::Reload { file_path } => {
let file_path = file_path.to_str().unwrap();
docs2.lock().unwrap().remove(file_path);
docs.lock().unwrap().remove(file_path);
let file_path = match crate::utils::canonicalize(file_path) {
Ok(p) => p.to_str().unwrap().to_owned(),
Err(e) => {
eprintln!("Error: {:?}", e);
return;
}
};
docs2.lock().unwrap().remove(&file_path);
docs.lock().unwrap().remove(&file_path);
}
repl_cmd::Commands::Watch { dir } => {
let dir = match crate::utils::canonicalize(dir) {
Ok(p) => p.to_str().unwrap().to_owned(),
Err(e) => {
eprintln!("Error: {:?}", e);
return;
}
};
watcher
.watch(Path::new(&dir), RecursiveMode::Recursive)
.expect("watch failed");
}
repl_cmd::Commands::Config => {
let src = docs2.lock().unwrap();
let conf = src.get(REPL_VIRTUAL_CONF).unwrap();
println!("{}", conf.text(&db2));
}
repl_cmd::Commands::Symbol => {
let vars = REPL_VARIABLES.lock().unwrap();
let mut src = "".to_string();
for (k, _) in vars.iter() {
src.push_str(&format!("println!(\"{}: \", {});\n", k, k));
}
drop(vars);
let id =
REPL_COUNTER.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
let anon_fn = format!(
"{}\n pub fn __anon__{}() void {{ \n{};\nreturn; }}",
used_headers, id, src
);
docs.lock()
.unwrap()
.get(REPL_VIRTUAL_ENTRY)
.unwrap()
.set_text(&mut db)
.to(anon_fn.clone());
mem.set_docs(&mut db)
.to(Arc::new(Mutex::new(docs.lock().unwrap().clone())));
let _ = compiler::compile_dry(&db, mem).unwrap();
load_mod_and_evaluate(&db, mem, &ctx);
}
})
.is_some()
{
Expand Down Expand Up @@ -268,6 +325,10 @@ project = "repl"
let mut errs_num = 0;
let mut warn_num = 0;
print_diags(diags, mem_check, &db2, &mut errs_num, &mut warn_num, true);
#[cfg(test)]
{
rl.assert_err(errs_num > 0);
}
if errs_num > 0 {
REPL_COUNTER.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
continue;
Expand Down Expand Up @@ -300,55 +361,7 @@ project = "repl"
.unwrap()
.extend(plmodule.global_table.clone());

let mods = compiler::compile_dry::accumulated::<ModBuffer>(&db, mem);

for m in &mods {
if !m.name.starts_with("__anon__") {
if LOADED_SET.lock().unwrap().contains(&m.path) {
continue;
}
unsafe {
let mo = Module::parse_bitcode_from_buffer(
&MemoryBuffer::create_from_memory_range(
&m.buf,
m.path.file_name().unwrap().to_str().unwrap(),
),
&ctx,
)
.unwrap();
let p = mo.as_mut_ptr();
mo.strip_debug_info();
log::trace!("Loaded module, content:\n{}", mo.to_string());
LOADED_SET.lock().unwrap().insert(m.path.clone());
immix::AddModuleToOrcJIT(p as _);
// Owned by the JIT now
std::mem::forget(mo);

log::info!("Loaded module: {:?}", m.name);
};
}
}
for m in &mods {
if m.name.starts_with("__anon__") {
unsafe {
let m = Module::parse_bitcode_from_buffer(
&MemoryBuffer::create_from_memory_range(
&m.buf,
m.path.file_name().unwrap().to_str().unwrap(),
),
&ctx,
)
.unwrap();

let p = m.as_mut_ptr();
m.strip_debug_info();
log::trace!("Evaluate module, content:\n{}", m.to_string());
immix::RunExpr(p as _);
// Owned by the JIT now
std::mem::forget(m);
}
}
}
load_mod_and_evaluate(&db, mem, &ctx);
}
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
Expand All @@ -368,6 +381,58 @@ project = "repl"
// exit(0);
}

fn load_mod_and_evaluate(db: &Database, mem: MemDocsInput, ctx: &Context) {
let mods = compiler::compile_dry::accumulated::<ModBuffer>(db, mem);

for m in &mods {
if !m.name.starts_with("__anon__") {
if LOADED_SET.lock().unwrap().contains(&m.path) {
continue;
}
unsafe {
let mo = Module::parse_bitcode_from_buffer(
&MemoryBuffer::create_from_memory_range(
&m.buf,
m.path.file_name().unwrap().to_str().unwrap(),
),
ctx,
)
.unwrap();
let p = mo.as_mut_ptr();
mo.strip_debug_info();
log::trace!("Loaded module, content:\n{}", mo.to_string());
LOADED_SET.lock().unwrap().insert(m.path.clone());
immix::AddModuleToOrcJIT(p as _);
// Owned by the JIT now
std::mem::forget(mo);

log::info!("Loaded module: {:?}", m.name);
};
}
}
for m in &mods {
if m.name.starts_with("__anon__") {
unsafe {
let m = Module::parse_bitcode_from_buffer(
&MemoryBuffer::create_from_memory_range(
&m.buf,
m.path.file_name().unwrap().to_str().unwrap(),
),
ctx,
)
.unwrap();

let p = m.as_mut_ptr();
m.strip_debug_info();
log::trace!("Evaluate module, content:\n{}", m.to_string());
immix::RunExpr(p as _);
// Owned by the JIT now
std::mem::forget(m);
}
}
}
}

fn validate_proj_cfg(
proj_path: &PathBuf,
db2: &Database,
Expand Down Expand Up @@ -477,3 +542,6 @@ fn new_watcher(sender: Sender<PathBuf>) -> notify::RecommendedWatcher {
})
.expect("create watcher failed")
}

#[cfg(test)]
mod test;
4 changes: 4 additions & 0 deletions src/repl/repl_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ pub enum Commands {
/// directory
dir: String,
},
/// Print current config
Config,
/// Print symbol table
Symbol,
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 59d1d22

Please sign in to comment.