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 {
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 {
module: Box::leak(path.to_str().unwrap().to_string().into_boxed_str()),
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)
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) {
Command::new("cmd")
.arg("/C")
@ -70,7 +70,7 @@ pub fn exec_pyc<S: Into<String>>(file: S) {
.spawn()
.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)
@ -94,19 +94,20 @@ pub fn eval_pyc<S: Into<String>>(file: S) -> String {
String::from_utf8_lossy(&out.stdout).to_string()
}
pub fn exec_py(code: &str) {
if cfg!(windows) {
pub fn exec_py(code: &str) -> Option<i32> {
let mut child = if cfg!(windows) {
Command::new(which_python())
.arg("-c")
.arg(code)
.spawn()
.expect("cannot execute python");
.expect("cannot execute python")
} else {
let python_command = format!("{} -c \"{}\"", which_python(), code);
Command::new("sh")
.arg("-c")
.arg(python_command)
.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 clear(&mut self);
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 {
&self.cfg().input

View file

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

View file

@ -129,9 +129,10 @@ impl Runnable for Compiler {
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");
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> {

View file

@ -888,7 +888,7 @@ impl Context {
if mod_cache.get(&path).is_some() {
return Ok(path);
}
let cfg = ErgConfig::with_path(path.clone());
let cfg = ErgConfig::with_module_path(path.clone());
let src = cfg.input.read();
let mut builder =
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() {
return Ok(path);
}
let cfg = ErgConfig::with_path(path.clone());
let cfg = ErgConfig::with_module_path(path.clone());
let src = cfg.input.read();
let mut builder =
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();
}
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 ast = ast_builder.build(self.input().read())?;
let (hir, warns) = self.lower(ast, "exec").map_err(|(_, errs)| errs)?;
@ -90,7 +90,7 @@ impl Runnable for ASTLowerer {
warns.fmt_all_stderr();
}
println!("{hir}");
Ok(())
Ok(0)
}
fn eval(&mut self, src: String) -> Result<String, Self::Errs> {

View file

@ -37,13 +37,13 @@ impl Runnable for LexerRunner {
#[inline]
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 ts = lexer
.lex()
.map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?;
println!("{ts}");
Ok(())
Ok(0)
}
fn eval(&mut self, src: String) -> Result<String, LexerRunnerErrors> {

View file

@ -186,10 +186,10 @@ impl Runnable for ParserRunner {
#[inline]
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())?;
println!("{ast}");
Ok(())
Ok(0)
}
fn eval(&mut self, src: String) -> Result<String, ParserRunnerErrors> {

View file

@ -94,12 +94,21 @@ impl Runnable for DummyVM {
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
.compile_and_dump_as_pyc("o.pyc", self.input().read(), "exec")?;
exec_pyc("o.pyc");
remove_file("o.pyc").unwrap();
Ok(())
.compile_and_dump_as_pyc(&filename, self.input().read(), "exec")?;
let code = exec_pyc(&filename);
remove_file(&filename).unwrap();
Ok(code.unwrap_or(1))
}
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, Input};
use erg_common::error::MultiErrorFmt;
use erg_common::config::ErgConfig;
use erg_common::error::MultiErrorDisplay;
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(())
}
}
}