added basic tests

This commit is contained in:
mark 2023-04-30 22:21:27 +02:00
parent 657f282006
commit b83f54cb2d
12 changed files with 103 additions and 36 deletions

View File

@ -25,15 +25,15 @@ println(greeting)
println!(); println!();
if let Ok(file_contents) = fs::read_to_string(&temp_file) { if let Ok(file_contents) = fs::read_to_string(&temp_file) {
let mut file = let mut file =
crate::parse::file::File::new(file_contents, temp_file.to_path_buf()); crate::parsing::file::File::new(file_contents, temp_file.to_path_buf());
match crate::parse::parse::parse(&mut file) { match crate::parsing::parse::parse(&mut file) {
Ok(func) => { Ok(func) => {
println!(" - - - - -"); println!(" - - - - -");
let output = func.run(vec![]); let output = func.run(vec![]);
println!(" - - - - -"); println!(" - - - - -");
println!("{}", output); println!("{}", output);
} }
Err(e) => println!("{}", e.0.with_file_and_gsinfo(&file, e.1.as_ref())), Err(e) => println!("{}", e.with_file(&file)),
} }
} else { } else {
println!("can't read file at {:?}!", temp_file); println!("can't read file at {:?}!", temp_file);

View File

@ -2,9 +2,9 @@
#![allow(dead_code)] #![allow(dead_code)]
mod libs; mod libs;
mod parse; mod parsing;
mod script; mod script;
pub use libs::inlib::*; pub use libs::inlib::*;
pub use parse::*; pub use parsing::*;
pub use script::{val_data::*, val_type::*}; pub use script::{val_data::*, val_type::*};

View File

@ -10,7 +10,7 @@ use std::{
}; };
use crate::{ use crate::{
parse::{file::File, parse}, parsing::{file::File, parse},
script::{ script::{
val_data::{VData, VDataEnum}, val_data::{VData, VDataEnum},
val_type::VType, val_type::VType,

View File

@ -9,7 +9,7 @@ mod interactive_mode;
mod libs; mod libs;
#[cfg(feature = "nushell_plugin")] #[cfg(feature = "nushell_plugin")]
mod nushell_plugin; mod nushell_plugin;
mod parse; mod parsing;
mod script; mod script;
mod tutor; mod tutor;
@ -105,7 +105,7 @@ fn normal_main() {
}; };
return; return;
} else if execute { } else if execute {
parse::file::File::new( parsing::file::File::new(
args.iter().skip(1).fold(String::new(), |mut s, v| { args.iter().skip(1).fold(String::new(), |mut s, v| {
if !s.is_empty() { if !s.is_empty() {
s.push(' '); s.push(' ');
@ -120,11 +120,11 @@ fn normal_main() {
std::process::exit(101); std::process::exit(101);
} }
} else { } 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) => { Ok(script) => {
println!(" - - - - -"); println!(" - - - - -");
let start = Instant::now(); let start = Instant::now();
@ -134,10 +134,7 @@ fn normal_main() {
println!("Output ({}s)\n{out}", elapsed.as_secs_f64()); println!("Output ({}s)\n{out}", elapsed.as_secs_f64());
} }
Err(e) => { Err(e) => {
println!( println!("Couldn't compile:\n{}", e.with_file(&file));
"Couldn't compile:\n{}",
e.0.with_file_and_gsinfo(&file, e.1.as_ref())
);
std::process::exit(99); std::process::exit(99);
} }
} }

View File

@ -1,4 +1,4 @@
use std::{process::Command, sync::Arc}; use std::{fmt::Debug, process::Command, sync::Arc};
use crate::{ use crate::{
libs, libs,
@ -6,7 +6,7 @@ use crate::{
code_macro::MacroError, code_macro::MacroError,
code_parsed::*, code_parsed::*,
code_runnable::RScript, code_runnable::RScript,
global_info::{GlobalScriptInfo, GSInfo}, global_info::{GSInfo, GlobalScriptInfo},
to_runnable::{self, ToRunnableError}, to_runnable::{self, ToRunnableError},
val_data::VDataEnum, val_data::VDataEnum,
val_type::{VSingleType, VType}, val_type::{VSingleType, VType},
@ -61,7 +61,11 @@ impl<'a> ScriptError {
pub fn with_gsinfo(&'a self, info: &'a GlobalScriptInfo) -> ScriptErrorWithInfo { pub fn with_gsinfo(&'a self, info: &'a GlobalScriptInfo) -> ScriptErrorWithInfo {
ScriptErrorWithInfo(self, info) 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) ScriptErrorWithFileAndInfo(self, file, info)
} }
} }
@ -82,7 +86,12 @@ impl<'a> std::fmt::Display for ScriptErrorWithFileAndInfo<'a> {
} }
impl ScriptError { 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 { match &self {
ScriptError::CannotFindPathForLibrary(e) => write!(f, "{e}"), ScriptError::CannotFindPathForLibrary(e) => write!(f, "{e}"),
ScriptError::ParseError(e) => { ScriptError::ParseError(e) => {
@ -102,28 +111,51 @@ impl ScriptError {
pub const PARSE_VERSION: u64 = 0; 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 /// executes the 4 parse_steps in order: lib_paths => interpret => libs_load => compile
pub fn parse(file: &mut File) -> Result<RScript, (ScriptError, GSInfo)> { pub fn parse(file: &mut File) -> Result<RScript, Error> {
let mut ginfo = GlobalScriptInfo::default(); let mut ginfo = GlobalScriptInfo::default();
let libs = match parse_step_lib_paths(file) { let libs = match parse_step_lib_paths(file) {
Ok(v) => v, 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) { let func = match parse_step_interpret(file) {
Ok(v) => v, 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) { ginfo.libs = match parse_step_libs_load(libs, &mut ginfo) {
Ok(v) => v, 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) { let run = match parse_step_compile(func, ginfo) {
Ok(v) => v, Ok(v) => v,
Err(e) => return Err((e.0.into(), e.1)), Err(e) => return Err((e.0.into(), e.1).into()),
}; };
Ok(run) Ok(run)
@ -198,7 +230,10 @@ pub fn parse_step_libs_load(
Ok(libs) Ok(libs)
} }
pub fn parse_step_compile(main_func: SFunction, ginfo: GlobalScriptInfo) -> Result<RScript, (ToRunnableError, GSInfo)> { pub fn parse_step_compile(
main_func: SFunction,
ginfo: GlobalScriptInfo,
) -> Result<RScript, (ToRunnableError, GSInfo)> {
to_runnable::to_runnable(main_func, ginfo) to_runnable::to_runnable(main_func, ginfo)
} }
@ -341,6 +376,8 @@ use implementation::*;
pub mod implementation { pub mod implementation {
use crate::parsing::file::FilePosition;
use super::*; use super::*;
fn parse_block(file: &mut File) -> Result<SBlock, ParseError> { fn parse_block(file: &mut File) -> Result<SBlock, ParseError> {
@ -733,7 +770,11 @@ pub mod implementation {
} }
"type" => { "type" => {
file.skip_whitespaces(); 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(), "true" => break SStatementEnum::Value(VDataEnum::Bool(true).to()).to(),
"false" => { "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 ...) <statement>" /// Assumes the function name and opening bracket have already been parsed. File should continue like "name type name type ...) <statement>"
fn parse_function( fn parse_function(
file: &mut File, file: &mut File,
err_fn_start: Option<crate::parse::file::FilePosition>, err_fn_start: Option<FilePosition>,
) -> Result<SFunction, ParseError> { ) -> Result<SFunction, ParseError> {
file.skip_whitespaces(); file.skip_whitespaces();
// find the arguments to the function // find the arguments to the function

View File

@ -1,6 +1,6 @@
use std::{fmt::Display, fs}; use std::{fmt::Display, fs};
use crate::parse::{ use crate::parsing::{
file::File, file::File,
parse::{self, ParseError, ScriptError}, parse::{self, ParseError, ScriptError},
}; };
@ -43,7 +43,7 @@ fn parse_mers_code(file: &mut File) -> Result<RScript, MacroError> {
_ = file.next(); _ = file.next();
match parse::parse(file) { match parse::parse(file) {
Ok(v) => Ok(v), Ok(v) => Ok(v),
Err(e) => Err(e.0.into()), Err(e) => Err(e.err.into()),
} }
} else { } else {
let path = parse_string_val(file); let path = parse_string_val(file);
@ -58,7 +58,7 @@ fn parse_mers_code(file: &mut File) -> Result<RScript, MacroError> {
); );
Ok(match parse::parse(&mut file) { Ok(match parse::parse(&mut file) {
Ok(v) => v, Ok(v) => v,
Err(e) => return Err(e.0.into()), Err(e) => return Err(e.err.into()),
}) })
} }
} }

View File

@ -1,8 +1,8 @@
use std::{path::PathBuf, thread::JoinHandle, time::Instant}; use std::{path::PathBuf, thread::JoinHandle, time::Instant};
use crate::{ use crate::{
parse::{self, parse::ScriptError, file::File}, parsing::{self, file::File, parse::ScriptError},
script::{code_runnable::RScript, val_data::VDataEnum, global_info::GSInfo}, script::{code_runnable::RScript, global_info::GSInfo, val_data::VDataEnum},
}; };
mod base_comments; mod base_comments;
@ -30,8 +30,8 @@ false
", ",
Box::new(move |file| { Box::new(move |file| {
let mut file = let mut file =
parse::file::File::new(std::fs::read_to_string(file).unwrap(), PathBuf::new()); parsing::file::File::new(std::fs::read_to_string(file).unwrap(), PathBuf::new());
sender.send((parse::parse::parse(&mut file), file)).unwrap(); sender.send((parsing::parse::parse(&mut file), file)).unwrap();
}), }),
) )
.unwrap(); .unwrap();
@ -60,7 +60,7 @@ pub struct Tutor {
written_status_byte_len: usize, written_status_byte_len: usize,
editor_join_handle: JoinHandle<()>, editor_join_handle: JoinHandle<()>,
file_path: PathBuf, file_path: PathBuf,
receiver: std::sync::mpsc::Receiver<(Result<RScript, (ScriptError, GSInfo)>, File)>, receiver: std::sync::mpsc::Receiver<(Result<RScript, parsing::parse::Error>, File)>,
// i_ are inputs from the user // i_ are inputs from the user
pub i_name: Option<String>, pub i_name: Option<String>,
} }
@ -70,10 +70,11 @@ impl Tutor {
// eprintln!(" - - - - - - - - - - - - - - - - - - - - - - - - -"); // eprintln!(" - - - - - - - - - - - - - - - - - - - - - - - - -");
let script = loop { let script = loop {
match self.receiver.recv().unwrap() { match self.receiver.recv().unwrap() {
(Err((e, info)), file) => { (Err(e), file) => {
self.current_status = format!( self.current_status = format!(
" - Error during build{}", " - Error during build{}",
e.with_file_and_gsinfo(&file, info.as_ref()).to_string() e.with_file(&file)
.to_string()
.lines() .lines()
.map(|v| format!("\n// {v}")) .map(|v| format!("\n// {v}"))
.collect::<String>() .collect::<String>()

View File

@ -0,0 +1 @@
true

View File

@ -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)
));
}
}
}
}

View File

@ -0,0 +1,3 @@
var: [string ...] = [...]
&var.push("a string")
var.len().eq(1)