Add execution test

This commit is contained in:
Shunsuke Shibayama 2022-10-01 01:11:31 +09:00
parent d6e06a02c0
commit 423206920a
11 changed files with 135 additions and 34 deletions

View file

@ -180,7 +180,15 @@ impl Default for ErgConfig {
} }
impl ErgConfig { impl ErgConfig {
pub fn with_path(path: PathBuf) -> Self { pub fn with_main_path(path: PathBuf) -> Self {
Self {
module: "<module>",
input: Input::File(path),
..ErgConfig::default()
}
}
pub fn with_module_path(path: PathBuf) -> Self {
Self { Self {
module: Box::leak(path.to_str().unwrap().to_string().into_boxed_str()), module: Box::leak(path.to_str().unwrap().to_string().into_boxed_str()),
input: Input::File(path), input: Input::File(path),

View file

@ -54,7 +54,7 @@ pub fn detect_magic_number() -> u32 {
} }
/// executes over a shell, cause `python` may not exist as an executable file (like pyenv) /// executes over a shell, cause `python` may not exist as an executable file (like pyenv)
pub fn exec_pyc<S: Into<String>>(file: S) { pub fn exec_pyc<S: Into<String>>(file: S) -> Option<i32> {
let mut out = if cfg!(windows) { let mut out = if cfg!(windows) {
Command::new("cmd") Command::new("cmd")
.arg("/C") .arg("/C")
@ -70,7 +70,7 @@ pub fn exec_pyc<S: Into<String>>(file: S) {
.spawn() .spawn()
.expect("cannot execute python") .expect("cannot execute python")
}; };
out.wait().expect("python doesn't work"); out.wait().expect("python doesn't work").code()
} }
/// evaluates over a shell, cause `python` may not exist as an executable file (like pyenv) /// evaluates over a shell, cause `python` may not exist as an executable file (like pyenv)
@ -94,19 +94,20 @@ pub fn eval_pyc<S: Into<String>>(file: S) -> String {
String::from_utf8_lossy(&out.stdout).to_string() String::from_utf8_lossy(&out.stdout).to_string()
} }
pub fn exec_py(code: &str) { pub fn exec_py(code: &str) -> Option<i32> {
if cfg!(windows) { let mut child = if cfg!(windows) {
Command::new(which_python()) Command::new(which_python())
.arg("-c") .arg("-c")
.arg(code) .arg(code)
.spawn() .spawn()
.expect("cannot execute python"); .expect("cannot execute python")
} else { } else {
let python_command = format!("{} -c \"{}\"", which_python(), code); let python_command = format!("{} -c \"{}\"", which_python(), code);
Command::new("sh") Command::new("sh")
.arg("-c") .arg("-c")
.arg(python_command) .arg(python_command)
.spawn() .spawn()
.expect("cannot execute python"); .expect("cannot execute python")
} };
child.wait().expect("python doesn't work").code()
} }

View file

@ -359,7 +359,7 @@ pub trait Runnable: Sized {
fn finish(&mut self); // called when the :exit command is received. fn finish(&mut self); // called when the :exit command is received.
fn clear(&mut self); fn clear(&mut self);
fn eval(&mut self, src: String) -> Result<String, Self::Errs>; fn eval(&mut self, src: String) -> Result<String, Self::Errs>;
fn exec(&mut self) -> Result<(), Self::Errs>; fn exec(&mut self) -> Result<i32, Self::Errs>;
fn input(&self) -> &Input { fn input(&self) -> &Input {
&self.cfg().input &self.cfg().input

View file

@ -45,12 +45,12 @@ impl Runnable for HIRBuilder {
fn clear(&mut self) {} fn clear(&mut self) {}
fn exec(&mut self) -> Result<(), Self::Errs> { fn exec(&mut self) -> Result<i32, Self::Errs> {
let mut builder = ASTBuilder::new(self.cfg().copy()); let mut builder = ASTBuilder::new(self.cfg().copy());
let ast = builder.build(self.input().read())?; let ast = builder.build(self.input().read())?;
let hir = self.check(ast, "exec").map_err(|(_, errs)| errs)?; let hir = self.check(ast, "exec").map_err(|(_, errs)| errs)?;
println!("{hir}"); println!("{hir}");
Ok(()) Ok(0)
} }
fn eval(&mut self, src: String) -> Result<String, Self::Errs> { fn eval(&mut self, src: String) -> Result<String, Self::Errs> {

View file

@ -129,9 +129,10 @@ impl Runnable for Compiler {
self.code_generator.clear(); self.code_generator.clear();
} }
fn exec(&mut self) -> Result<(), Self::Errs> { fn exec(&mut self) -> Result<i32, Self::Errs> {
let path = self.input().filename().replace(".er", ".pyc"); let path = self.input().filename().replace(".er", ".pyc");
self.compile_and_dump_as_pyc(path, self.input().read(), "exec") self.compile_and_dump_as_pyc(path, self.input().read(), "exec")?;
Ok(0)
} }
fn eval(&mut self, src: String) -> Result<String, CompileErrors> { fn eval(&mut self, src: String) -> Result<String, CompileErrors> {

View file

@ -888,7 +888,7 @@ impl Context {
if mod_cache.get(&path).is_some() { if mod_cache.get(&path).is_some() {
return Ok(path); return Ok(path);
} }
let cfg = ErgConfig::with_path(path.clone()); let cfg = ErgConfig::with_module_path(path.clone());
let src = cfg.input.read(); let src = cfg.input.read();
let mut builder = let mut builder =
HIRBuilder::new_with_cache(cfg, __name__, mod_cache.clone(), py_mod_cache.clone()); HIRBuilder::new_with_cache(cfg, __name__, mod_cache.clone(), py_mod_cache.clone());
@ -986,7 +986,7 @@ impl Context {
if py_mod_cache.get(&path).is_some() { if py_mod_cache.get(&path).is_some() {
return Ok(path); return Ok(path);
} }
let cfg = ErgConfig::with_path(path.clone()); let cfg = ErgConfig::with_module_path(path.clone());
let src = cfg.input.read(); let src = cfg.input.read();
let mut builder = let mut builder =
HIRBuilder::new_with_cache(cfg, __name__, py_mod_cache.clone(), py_mod_cache.clone()); HIRBuilder::new_with_cache(cfg, __name__, py_mod_cache.clone(), py_mod_cache.clone());

View file

@ -82,7 +82,7 @@ impl Runnable for ASTLowerer {
self.warns.clear(); self.warns.clear();
} }
fn exec(&mut self) -> Result<(), Self::Errs> { fn exec(&mut self) -> Result<i32, Self::Errs> {
let mut ast_builder = ASTBuilder::new(self.cfg.copy()); let mut ast_builder = ASTBuilder::new(self.cfg.copy());
let ast = ast_builder.build(self.input().read())?; let ast = ast_builder.build(self.input().read())?;
let (hir, warns) = self.lower(ast, "exec").map_err(|(_, errs)| errs)?; let (hir, warns) = self.lower(ast, "exec").map_err(|(_, errs)| errs)?;
@ -90,7 +90,7 @@ impl Runnable for ASTLowerer {
warns.fmt_all_stderr(); warns.fmt_all_stderr();
} }
println!("{hir}"); println!("{hir}");
Ok(()) Ok(0)
} }
fn eval(&mut self, src: String) -> Result<String, Self::Errs> { fn eval(&mut self, src: String) -> Result<String, Self::Errs> {

View file

@ -37,13 +37,13 @@ impl Runnable for LexerRunner {
#[inline] #[inline]
fn clear(&mut self) {} fn clear(&mut self) {}
fn exec(&mut self) -> Result<(), Self::Errs> { fn exec(&mut self) -> Result<i32, Self::Errs> {
let lexer = Lexer::from_str(self.input().read()); let lexer = Lexer::from_str(self.input().read());
let ts = lexer let ts = lexer
.lex() .lex()
.map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?; .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?;
println!("{ts}"); println!("{ts}");
Ok(()) Ok(0)
} }
fn eval(&mut self, src: String) -> Result<String, LexerRunnerErrors> { fn eval(&mut self, src: String) -> Result<String, LexerRunnerErrors> {

View file

@ -186,10 +186,10 @@ impl Runnable for ParserRunner {
#[inline] #[inline]
fn clear(&mut self) {} fn clear(&mut self) {}
fn exec(&mut self) -> Result<(), Self::Errs> { fn exec(&mut self) -> Result<i32, Self::Errs> {
let ast = self.parse(self.input().read())?; let ast = self.parse(self.input().read())?;
println!("{ast}"); println!("{ast}");
Ok(()) Ok(0)
} }
fn eval(&mut self, src: String) -> Result<String, ParserRunnerErrors> { fn eval(&mut self, src: String) -> Result<String, ParserRunnerErrors> {

View file

@ -94,12 +94,21 @@ impl Runnable for DummyVM {
self.compiler.clear(); self.compiler.clear();
} }
fn exec(&mut self) -> Result<(), Self::Errs> { fn exec(&mut self) -> Result<i32, Self::Errs> {
// Parallel execution is not possible without dumping with a unique file name.
let filename = self
.cfg()
.input
.filename()
.split('/')
.last()
.unwrap()
.replace(".er", ".pyc");
self.compiler self.compiler
.compile_and_dump_as_pyc("o.pyc", self.input().read(), "exec")?; .compile_and_dump_as_pyc(&filename, self.input().read(), "exec")?;
exec_pyc("o.pyc"); let code = exec_pyc(&filename);
remove_file("o.pyc").unwrap(); remove_file(&filename).unwrap();
Ok(()) Ok(code.unwrap_or(1))
} }
fn eval(&mut self, src: String) -> Result<String, EvalErrors> { fn eval(&mut self, src: String) -> Result<String, EvalErrors> {

View file

@ -1,11 +1,93 @@
extern crate erg; use std::path::PathBuf;
mod tests { use erg_common::config::ErgConfig;
/* use erg_common::error::MultiErrorDisplay;
use erg_common::config::{ErgConfig, Input};
use erg_common::error::MultiErrorFmt;
use erg_common::traits::Runnable; use erg_common::traits::Runnable;
const FILE3: &str = "tests/test3_object_system.er"; use erg::dummy::DummyVM;
*/
#[test]
fn exec_class() -> Result<(), ()> {
expect_success("examples/class.er")
}
#[test]
fn exec_fib() -> Result<(), ()> {
expect_success("examples/fib.er")
}
#[test]
fn exec_hello_world() -> Result<(), ()> {
expect_success("examples/helloworld.er")
}
#[test]
fn exec_import() -> Result<(), ()> {
expect_success("examples/import.er")
}
#[test]
fn exec_move_check() -> Result<(), ()> {
expect_failure("examples/move_check.er")
}
#[test]
fn exec_record() -> Result<(), ()> {
expect_success("examples/record.er")
}
#[test]
fn exec_side_effect() -> Result<(), ()> {
expect_failure("examples/side_effect.er")
}
#[test]
fn exec_trait() -> Result<(), ()> {
expect_success("examples/trait.er")
}
#[test]
fn exec_tuple() -> Result<(), ()> {
expect_success("examples/tuple.er")
}
#[test]
fn exec_unpack() -> Result<(), ()> {
expect_success("examples/unpack.er")
}
#[test]
fn exec_use_py() -> Result<(), ()> {
expect_success("examples/use_py.er")
}
#[test]
fn exec_with() -> Result<(), ()> {
expect_success("examples/with.er")
}
fn expect_success(file_path: &'static str) -> Result<(), ()> {
let cfg = ErgConfig::with_main_path(PathBuf::from(file_path));
let mut vm = DummyVM::new(cfg);
match vm.exec() {
Ok(0) => Ok(()),
Ok(_) => Err(()),
Err(errs) => {
errs.fmt_all_stderr();
Err(())
}
}
}
fn expect_failure(file_path: &'static str) -> Result<(), ()> {
let cfg = ErgConfig::with_main_path(PathBuf::from(file_path));
let mut vm = DummyVM::new(cfg);
match vm.exec() {
Ok(0) => Err(()),
Ok(_) => Ok(()),
Err(errs) => {
errs.fmt_all_stderr();
Ok(())
}
}
} }