From b83f54cb2d083411f386815158700e881c3c3f18 Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 30 Apr 2023 22:21:27 +0200 Subject: [PATCH] added basic tests --- mers/src/interactive_mode.rs | 6 +-- mers/src/lib.rs | 4 +- mers/src/libs/mod.rs | 2 +- mers/src/main.rs | 13 +++--- mers/src/{parse => parsing}/file.rs | 0 mers/src/{parse => parsing}/mod.rs | 0 mers/src/{parse => parsing}/parse.rs | 65 +++++++++++++++++++++++----- mers/src/script/code_macro.rs | 6 +-- mers/src/tutor/mod.rs | 15 ++++--- mers/tests/return_true.mers | 1 + mers/tests/test_in_mers.rs | 24 ++++++++++ mers/tests/type_syntax.mers | 3 ++ 12 files changed, 103 insertions(+), 36 deletions(-) rename mers/src/{parse => parsing}/file.rs (100%) rename mers/src/{parse => parsing}/mod.rs (100%) rename mers/src/{parse => parsing}/parse.rs (96%) create mode 100644 mers/tests/return_true.mers create mode 100644 mers/tests/test_in_mers.rs create mode 100644 mers/tests/type_syntax.mers diff --git a/mers/src/interactive_mode.rs b/mers/src/interactive_mode.rs index 259a731..6ab3a86 100755 --- a/mers/src/interactive_mode.rs +++ b/mers/src/interactive_mode.rs @@ -25,15 +25,15 @@ println(greeting) println!(); if let Ok(file_contents) = fs::read_to_string(&temp_file) { let mut file = - crate::parse::file::File::new(file_contents, temp_file.to_path_buf()); - match crate::parse::parse::parse(&mut file) { + crate::parsing::file::File::new(file_contents, temp_file.to_path_buf()); + match crate::parsing::parse::parse(&mut file) { Ok(func) => { println!(" - - - - -"); let output = func.run(vec![]); println!(" - - - - -"); println!("{}", output); } - Err(e) => println!("{}", e.0.with_file_and_gsinfo(&file, e.1.as_ref())), + Err(e) => println!("{}", e.with_file(&file)), } } else { println!("can't read file at {:?}!", temp_file); diff --git a/mers/src/lib.rs b/mers/src/lib.rs index d0a0c79..b03a815 100755 --- a/mers/src/lib.rs +++ b/mers/src/lib.rs @@ -2,9 +2,9 @@ #![allow(dead_code)] mod libs; -mod parse; +mod parsing; mod script; pub use libs::inlib::*; -pub use parse::*; +pub use parsing::*; pub use script::{val_data::*, val_type::*}; diff --git a/mers/src/libs/mod.rs b/mers/src/libs/mod.rs index de39013..810722e 100755 --- a/mers/src/libs/mod.rs +++ b/mers/src/libs/mod.rs @@ -10,7 +10,7 @@ use std::{ }; use crate::{ - parse::{file::File, parse}, + parsing::{file::File, parse}, script::{ val_data::{VData, VDataEnum}, val_type::VType, diff --git a/mers/src/main.rs b/mers/src/main.rs index 5d3b511..d0fe834 100755 --- a/mers/src/main.rs +++ b/mers/src/main.rs @@ -9,7 +9,7 @@ mod interactive_mode; mod libs; #[cfg(feature = "nushell_plugin")] mod nushell_plugin; -mod parse; +mod parsing; mod script; mod tutor; @@ -105,7 +105,7 @@ fn normal_main() { }; return; } else if execute { - parse::file::File::new( + parsing::file::File::new( args.iter().skip(1).fold(String::new(), |mut s, v| { if !s.is_empty() { s.push(' '); @@ -120,11 +120,11 @@ fn normal_main() { std::process::exit(101); } } else { - parse::file::File::new(std::fs::read_to_string(&args[0]).unwrap(), path.into()) + parsing::file::File::new(std::fs::read_to_string(&args[0]).unwrap(), path.into()) } } }; - match parse::parse::parse(&mut file) { + match parsing::parse::parse(&mut file) { Ok(script) => { println!(" - - - - -"); let start = Instant::now(); @@ -134,10 +134,7 @@ fn normal_main() { println!("Output ({}s)\n{out}", elapsed.as_secs_f64()); } Err(e) => { - println!( - "Couldn't compile:\n{}", - e.0.with_file_and_gsinfo(&file, e.1.as_ref()) - ); + println!("Couldn't compile:\n{}", e.with_file(&file)); std::process::exit(99); } } diff --git a/mers/src/parse/file.rs b/mers/src/parsing/file.rs similarity index 100% rename from mers/src/parse/file.rs rename to mers/src/parsing/file.rs diff --git a/mers/src/parse/mod.rs b/mers/src/parsing/mod.rs similarity index 100% rename from mers/src/parse/mod.rs rename to mers/src/parsing/mod.rs diff --git a/mers/src/parse/parse.rs b/mers/src/parsing/parse.rs similarity index 96% rename from mers/src/parse/parse.rs rename to mers/src/parsing/parse.rs index 4494fd7..9b944f9 100755 --- a/mers/src/parse/parse.rs +++ b/mers/src/parsing/parse.rs @@ -1,4 +1,4 @@ -use std::{process::Command, sync::Arc}; +use std::{fmt::Debug, process::Command, sync::Arc}; use crate::{ libs, @@ -6,7 +6,7 @@ use crate::{ code_macro::MacroError, code_parsed::*, code_runnable::RScript, - global_info::{GlobalScriptInfo, GSInfo}, + global_info::{GSInfo, GlobalScriptInfo}, to_runnable::{self, ToRunnableError}, val_data::VDataEnum, val_type::{VSingleType, VType}, @@ -61,7 +61,11 @@ impl<'a> ScriptError { pub fn with_gsinfo(&'a self, info: &'a GlobalScriptInfo) -> ScriptErrorWithInfo { ScriptErrorWithInfo(self, info) } - pub fn with_file_and_gsinfo(&'a self, file: &'a File, info: &'a GlobalScriptInfo) -> ScriptErrorWithFileAndInfo { + pub fn with_file_and_gsinfo( + &'a self, + file: &'a File, + info: &'a GlobalScriptInfo, + ) -> ScriptErrorWithFileAndInfo { ScriptErrorWithFileAndInfo(self, file, info) } } @@ -82,7 +86,12 @@ impl<'a> std::fmt::Display for ScriptErrorWithFileAndInfo<'a> { } impl ScriptError { - fn fmt_custom(&self, f: &mut std::fmt::Formatter<'_>, file: Option<&File>, info: Option<&GlobalScriptInfo>) -> std::fmt::Result { + fn fmt_custom( + &self, + f: &mut std::fmt::Formatter<'_>, + file: Option<&File>, + info: Option<&GlobalScriptInfo>, + ) -> std::fmt::Result { match &self { ScriptError::CannotFindPathForLibrary(e) => write!(f, "{e}"), ScriptError::ParseError(e) => { @@ -102,28 +111,51 @@ impl ScriptError { pub const PARSE_VERSION: u64 = 0; +pub struct Error { + pub err: ScriptError, + pub ginfo: GSInfo, +} +impl From<(ScriptError, GSInfo)> for Error { + fn from(value: (ScriptError, GSInfo)) -> Self { + Self { + err: value.0, + ginfo: value.1, + } + } +} +impl Debug for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.err.with_gsinfo(&self.ginfo)) + } +} +impl Error { + pub fn with_file<'a>(&'a self, file: &'a File) -> ScriptErrorWithFileAndInfo<'a> { + self.err.with_file_and_gsinfo(file, self.ginfo.as_ref()) + } +} + /// executes the 4 parse_steps in order: lib_paths => interpret => libs_load => compile -pub fn parse(file: &mut File) -> Result { +pub fn parse(file: &mut File) -> Result { let mut ginfo = GlobalScriptInfo::default(); let libs = match parse_step_lib_paths(file) { Ok(v) => v, - Err(e) => return Err((e.into(), ginfo.to_arc())), + Err(e) => return Err((e.into(), ginfo.to_arc()).into()), }; let func = match parse_step_interpret(file) { Ok(v) => v, - Err(e) => return Err((e.into(), ginfo.to_arc())), + Err(e) => return Err((e.into(), ginfo.to_arc()).into()), }; ginfo.libs = match parse_step_libs_load(libs, &mut ginfo) { Ok(v) => v, - Err(e) => return Err((e.into(), ginfo.to_arc())), + Err(e) => return Err((e.into(), ginfo.to_arc()).into()), }; let run = match parse_step_compile(func, ginfo) { Ok(v) => v, - Err(e) => return Err((e.0.into(), e.1)), + Err(e) => return Err((e.0.into(), e.1).into()), }; Ok(run) @@ -198,7 +230,10 @@ pub fn parse_step_libs_load( Ok(libs) } -pub fn parse_step_compile(main_func: SFunction, ginfo: GlobalScriptInfo) -> Result { +pub fn parse_step_compile( + main_func: SFunction, + ginfo: GlobalScriptInfo, +) -> Result { to_runnable::to_runnable(main_func, ginfo) } @@ -341,6 +376,8 @@ use implementation::*; pub mod implementation { + use crate::parsing::file::FilePosition; + use super::*; fn parse_block(file: &mut File) -> Result { @@ -733,7 +770,11 @@ pub mod implementation { } "type" => { file.skip_whitespaces(); - break SStatementEnum::TypeDefinition(file.collect_to_whitespace(), parse_type(file)?).to(); + break SStatementEnum::TypeDefinition( + file.collect_to_whitespace(), + parse_type(file)?, + ) + .to(); } "true" => break SStatementEnum::Value(VDataEnum::Bool(true).to()).to(), "false" => { @@ -940,7 +981,7 @@ pub mod implementation { /// Assumes the function name and opening bracket have already been parsed. File should continue like "name type name type ...) " fn parse_function( file: &mut File, - err_fn_start: Option, + err_fn_start: Option, ) -> Result { file.skip_whitespaces(); // find the arguments to the function diff --git a/mers/src/script/code_macro.rs b/mers/src/script/code_macro.rs index 8a7f736..d0889ba 100755 --- a/mers/src/script/code_macro.rs +++ b/mers/src/script/code_macro.rs @@ -1,6 +1,6 @@ use std::{fmt::Display, fs}; -use crate::parse::{ +use crate::parsing::{ file::File, parse::{self, ParseError, ScriptError}, }; @@ -43,7 +43,7 @@ fn parse_mers_code(file: &mut File) -> Result { _ = file.next(); match parse::parse(file) { Ok(v) => Ok(v), - Err(e) => Err(e.0.into()), + Err(e) => Err(e.err.into()), } } else { let path = parse_string_val(file); @@ -58,7 +58,7 @@ fn parse_mers_code(file: &mut File) -> Result { ); Ok(match parse::parse(&mut file) { Ok(v) => v, - Err(e) => return Err(e.0.into()), + Err(e) => return Err(e.err.into()), }) } } diff --git a/mers/src/tutor/mod.rs b/mers/src/tutor/mod.rs index 4ef31af..e9d9815 100755 --- a/mers/src/tutor/mod.rs +++ b/mers/src/tutor/mod.rs @@ -1,8 +1,8 @@ use std::{path::PathBuf, thread::JoinHandle, time::Instant}; use crate::{ - parse::{self, parse::ScriptError, file::File}, - script::{code_runnable::RScript, val_data::VDataEnum, global_info::GSInfo}, + parsing::{self, file::File, parse::ScriptError}, + script::{code_runnable::RScript, global_info::GSInfo, val_data::VDataEnum}, }; mod base_comments; @@ -30,8 +30,8 @@ false ", Box::new(move |file| { let mut file = - parse::file::File::new(std::fs::read_to_string(file).unwrap(), PathBuf::new()); - sender.send((parse::parse::parse(&mut file), file)).unwrap(); + parsing::file::File::new(std::fs::read_to_string(file).unwrap(), PathBuf::new()); + sender.send((parsing::parse::parse(&mut file), file)).unwrap(); }), ) .unwrap(); @@ -60,7 +60,7 @@ pub struct Tutor { written_status_byte_len: usize, editor_join_handle: JoinHandle<()>, file_path: PathBuf, - receiver: std::sync::mpsc::Receiver<(Result, File)>, + receiver: std::sync::mpsc::Receiver<(Result, File)>, // i_ are inputs from the user pub i_name: Option, } @@ -70,10 +70,11 @@ impl Tutor { // eprintln!(" - - - - - - - - - - - - - - - - - - - - - - - - -"); let script = loop { match self.receiver.recv().unwrap() { - (Err((e, info)), file) => { + (Err(e), file) => { self.current_status = format!( " - Error during build{}", - e.with_file_and_gsinfo(&file, info.as_ref()).to_string() + e.with_file(&file) + .to_string() .lines() .map(|v| format!("\n// {v}")) .collect::() diff --git a/mers/tests/return_true.mers b/mers/tests/return_true.mers new file mode 100644 index 0000000..27ba77d --- /dev/null +++ b/mers/tests/return_true.mers @@ -0,0 +1 @@ +true diff --git a/mers/tests/test_in_mers.rs b/mers/tests/test_in_mers.rs new file mode 100644 index 0000000..5192de1 --- /dev/null +++ b/mers/tests/test_in_mers.rs @@ -0,0 +1,24 @@ +use std::{fs, path::Path}; + +use mers_libs::file::File; +use mers_libs::{parse, VDataEnum}; + +#[test] +fn run_all() { + for file in fs::read_dir(Path::new(file!()).parent().unwrap()) + .unwrap() + .filter_map(|v| v.ok()) + { + if let Some(file_name) = file.file_name().to_str() { + if file_name.ends_with(".mers") { + eprintln!("Checking {}", file_name); + let mut file = File::new(fs::read_to_string(file.path()).unwrap(), file.path()); + // has to return true, otherwise the test will fail + assert!(matches!( + parse::parse(&mut file).unwrap().run(vec![]).data, + VDataEnum::Bool(true) + )); + } + } + } +} diff --git a/mers/tests/type_syntax.mers b/mers/tests/type_syntax.mers new file mode 100644 index 0000000..92279ff --- /dev/null +++ b/mers/tests/type_syntax.mers @@ -0,0 +1,3 @@ +var: [string ...] = [...] +&var.push("a string") +var.len().eq(1)