From 46dbb13e0fb7d89397c3a2f917474897edb3eb21 Mon Sep 17 00:00:00 2001 From: mark Date: Tue, 6 Jun 2023 15:22:45 +0200 Subject: [PATCH] fixed warnings, cargo clippy, and mers-nu --- args.mers | 1 + mers/src/{libs/inlib.rs => inlib/mod.rs} | 41 +++++----- mers/src/lang/builtins.rs | 43 +++++++---- mers/src/lang/code_macro.rs | 12 ++- mers/src/lang/code_parsed.rs | 13 +--- mers/src/lang/code_runnable.rs | 81 ++++++++++---------- mers/src/lang/fmtgs.rs | 6 +- mers/src/lang/global_info.rs | 21 +---- mers/src/lang/to_runnable.rs | 42 +++------- mers/src/lang/val_data.rs | 43 +++++------ mers/src/lang/val_type.rs | 10 +-- mers/src/lib.rs | 8 +- mers/src/libs/comms.rs | 8 +- mers/src/libs/mod.rs | 49 +++++++----- mers/src/main.rs | 15 ++-- mers/src/nushell_plugin.rs | 97 +++++++++++++++++------- mers/src/parsing/parse.rs | 27 +++---- mers/src/{libs/path.rs => pathutil.rs} | 16 ++-- mers/src/tutor/mod.rs | 6 +- 19 files changed, 280 insertions(+), 259 deletions(-) create mode 100644 args.mers rename mers/src/{libs/inlib.rs => inlib/mod.rs} (80%) rename mers/src/{libs/path.rs => pathutil.rs} (60%) diff --git a/args.mers b/args.mers new file mode 100644 index 0000000..e1e1410 --- /dev/null +++ b/args.mers @@ -0,0 +1 @@ +args.debug() diff --git a/mers/src/libs/inlib.rs b/mers/src/inlib/mod.rs similarity index 80% rename from mers/src/libs/inlib.rs rename to mers/src/inlib/mod.rs index edf77af..fd3b4ea 100755 --- a/mers/src/libs/inlib.rs +++ b/mers/src/inlib/mod.rs @@ -1,12 +1,9 @@ -use std::{ - collections::HashMap, - io::{BufRead, Stdin, StdinLock, Stdout, StdoutLock, Write}, -}; +use std::io::{Stdin, StdinLock, Write}; -use crate::lang::{val_data::VData, val_type::VType}; +use crate::lang::val_type::VType; -use super::{ - comms::{self, ByteData, ByteDataA, Message, MessageResponse, RespondableMessage}, +use super::libs::{ + comms::{self, ByteData, ByteDataA, Message, RespondableMessage}, LibInitInfo, LibInitReq, }; @@ -18,6 +15,7 @@ pub struct MyLib { pub callbacks: Callbacks, enum_variants: Vec<(String, usize)>, stdin: StdinLock<'static>, + #[allow(unused)] stdin_no_lock: Stdin, } impl MyLib { @@ -32,12 +30,14 @@ impl MyLib { let mut stdout = stdout_no_lock.lock(); let mut stdin = stdin_no_lock.lock(); // comms version - stdout.write(1u128.as_byte_data_vec().as_slice()).unwrap(); + stdout + .write_all(1u128.as_byte_data_vec().as_slice()) + .unwrap(); let init_req: LibInitReq = (version.0, version.1, name, description, functions); stdout - .write(init_req.as_byte_data_vec().as_slice()) + .write_all(init_req.as_byte_data_vec().as_slice()) .unwrap(); - stdout.flush(); + stdout.flush().unwrap(); let enum_variants = LibInitInfo::from_byte_data(&mut stdin).unwrap(); Self { // name: name.clone(), @@ -56,10 +56,13 @@ impl MyLib { fn get_one_msg(&mut self) -> Result, std::io::Error> { let id = u128::from_byte_data(&mut self.stdin)?; let message = Message::from_byte_data(&mut self.stdin)?; - match message { - Message::RunFunction(msg) => self.callbacks.run_function.run(Respondable::new(id, msg)), - }; - Ok(Ok(())) + Ok(match message { + Message::RunFunction(msg) => self + .callbacks + .run_function + .run(Respondable::new(id, msg)) + .map_err(|e| Message::RunFunction(e.msg)), + }) } pub fn get_next_unhandled_message(&mut self) -> Result<(), Message> { loop { @@ -68,7 +71,7 @@ impl MyLib { // unhandled message. return it to be handeled or included in the error Ok(Err(msg)) => return Err(msg), // i/o error, probably because mers exited. return successfully. - Err(e) => return Ok(()), + Err(_e) => return Ok(()), } } } @@ -89,9 +92,9 @@ where { pub fn respond(self, with: M::With) { let mut stdout = std::io::stdout().lock(); - stdout.write(&self.id.as_byte_data_vec()).unwrap(); + stdout.write_all(&self.id.as_byte_data_vec()).unwrap(); stdout - .write(&self.msg.respond(with).as_byte_data_vec()) + .write_all(&self.msg.respond(with).as_byte_data_vec()) .unwrap(); stdout.flush().unwrap(); } @@ -117,14 +120,14 @@ impl Callbacks { } pub struct Callback where - M: super::comms::RespondableMessage, + M: RespondableMessage, { pub nonconsuming: Vec>, pub consuming: Option)>>, } impl Callback where - M: super::comms::RespondableMessage, + M: RespondableMessage, { pub fn empty() -> Self { Self { diff --git a/mers/src/lang/builtins.rs b/mers/src/lang/builtins.rs index 0d5cbc7..c4342ce 100755 --- a/mers/src/lang/builtins.rs +++ b/mers/src/lang/builtins.rs @@ -1,11 +1,4 @@ -use std::{ - io::Write, - path::PathBuf, - sync::{Arc, Mutex}, - time::Duration, -}; - -use crate::libs; +use std::{io::Write, path::PathBuf, sync::Arc, time::Duration}; use super::{ code_runnable::RStatement, @@ -42,6 +35,7 @@ pub enum BuiltinFunction { Run, Thread, Await, + TryAwait, Sleep, Exit, // FS @@ -109,6 +103,7 @@ impl BuiltinFunction { "run" => Self::Run, "thread" => Self::Thread, "await" => Self::Await, + "try_await" => Self::TryAwait, "sleep" => Self::Sleep, "exit" => Self::Exit, // "command" => Self::Command, @@ -271,7 +266,7 @@ impl BuiltinFunction { false } } - Self::Await => { + Self::Await | Self::TryAwait => { input.len() == 1 && input[0] .types @@ -594,7 +589,7 @@ impl BuiltinFunction { unreachable!("run or thread called without args") } } - Self::Await => { + Self::Await | Self::TryAwait => { if let Some(v) = input.first() { let mut out = VType { types: vec![] }; for v in &v.types { @@ -604,7 +599,13 @@ impl BuiltinFunction { unreachable!("await called with non-thread arg") } } - out + if let Self::TryAwait = self { + let mut o = VSingleType::Tuple(vec![out]).to(); + o.add_type(VSingleType::Tuple(vec![]), info); + o + } else { + out + } } else { unreachable!("await called without args") } @@ -795,7 +796,7 @@ impl BuiltinFunction { pub fn run(&self, args: &Vec, info: &GSInfo) -> VData { match self { Self::Assume1 => { - let mut a0 = args[0].run(info); + let a0 = args[0].run(info); match a0.operate_on_data_immut(|v| { if let VDataEnum::Tuple(v) = v { if let Some(v) = v.get(0) { @@ -877,12 +878,12 @@ impl BuiltinFunction { #[cfg(not(feature = "nushell_plugin"))] { print!("{}", arg); - std::io::stdout().flush(); + _ = std::io::stdout().flush(); } #[cfg(feature = "nushell_plugin")] { eprint!("{}", arg); - std::io::stderr().flush(); + _ = std::io::stderr().flush(); } VDataEnum::Tuple(vec![]).to() } else { @@ -991,7 +992,7 @@ impl BuiltinFunction { var.lock().unwrap().0 = val; } let out_type = f - .out( + .out_by_map( &run_input_types.iter().map(|v| v.clone().into()).collect(), &info, ) @@ -1014,6 +1015,18 @@ impl BuiltinFunction { unreachable!() } }), + BuiltinFunction::TryAwait => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::Thread(t, _) = v { + if let Some(v) = t.try_get() { + VDataEnum::Tuple(vec![v]) + } else { + VDataEnum::Tuple(vec![]) + } + .to() + } else { + unreachable!() + } + }), BuiltinFunction::Sleep => args[0].run(info).operate_on_data_immut(|v| { match v { VDataEnum::Int(v) => std::thread::sleep(Duration::from_secs(*v as _)), diff --git a/mers/src/lang/code_macro.rs b/mers/src/lang/code_macro.rs index 3696d0f..c585c73 100755 --- a/mers/src/lang/code_macro.rs +++ b/mers/src/lang/code_macro.rs @@ -5,7 +5,9 @@ use crate::parsing::{ parse::{self, ParseError, ScriptError}, }; -use super::{code_parsed::SStatement, code_runnable::RScript, val_data::VData, val_type::VType}; +use crate::lang::val_data::VDataEnum; + +use super::{code_runnable::RScript, val_data::VData}; // macro format is !(macro_type [...]) @@ -30,7 +32,11 @@ pub fn parse_macro(file: &mut File) -> Result { } args.push(parse_string_val(file)); } - let val = code.run(args); + let val = code.run( + args.into_iter() + .map(|v| VDataEnum::String(v).to()) + .collect(), + ); if val.safe_to_share() { val } else { @@ -57,7 +63,7 @@ fn parse_mers_code(file: &mut File) -> Result { let path = parse_string_val(file); #[cfg(debug_assertions)] eprintln!("macro: mers: path: {path}"); - let path = crate::libs::path::path_from_string(path.as_str(), file.path()) + let path = crate::pathutil::path_from_string(path.as_str(), file.path(), false) .expect("can't include mers code because no file was found at that path"); let mut file = File::new( fs::read_to_string(&path) diff --git a/mers/src/lang/code_parsed.rs b/mers/src/lang/code_parsed.rs index b437847..c9c7f60 100755 --- a/mers/src/lang/code_parsed.rs +++ b/mers/src/lang/code_parsed.rs @@ -1,6 +1,4 @@ -use std::fmt::{self, Display, Formatter, Pointer}; - -use crate::lang::global_info::ColorFormatMode; +use std::fmt::{self, Display, Formatter}; use super::{ code_macro::Macro, fmtgs::FormatGs, global_info::GlobalScriptInfo, val_data::VData, @@ -61,11 +59,6 @@ impl SStatement { self.output_to = Some((Box::new(statement), true)); self } - // forces the statement's output to fit in a certain type. - pub fn force_output_type(mut self, force_output_type: Option) -> Self { - self.force_output_type = force_output_type; - self - } } /// A block of code is a collection of statements. @@ -115,7 +108,7 @@ impl FormatGs for SStatementEnum { } Self::List(v) => { write!(f, "{}", form.open_bracket(info, "[".to_owned()))?; - for (i, v) in v.iter().enumerate() { + for (_i, v) in v.iter().enumerate() { v.fmtgs(f, info, form, file)?; write!(f, " ")?; } @@ -136,7 +129,7 @@ impl FormatGs for SStatementEnum { )?; for (i, arg) in args.iter().enumerate() { if i != 0 { - write!(f, " "); + write!(f, " ")?; } arg.fmtgs(f, info, form, file)?; } diff --git a/mers/src/lang/code_runnable.rs b/mers/src/lang/code_runnable.rs index 68abdfd..8667bd7 100755 --- a/mers/src/lang/code_runnable.rs +++ b/mers/src/lang/code_runnable.rs @@ -1,8 +1,4 @@ -use std::{ - assert_eq, eprintln, - ops::Deref, - sync::{Arc, Mutex}, -}; +use std::sync::{Arc, Mutex}; use super::{ builtins::BuiltinFunction, @@ -66,7 +62,7 @@ pub struct RFunction { pub out_map: Vec<(Vec, VType)>, } impl PartialEq for RFunction { - fn eq(&self, other: &Self) -> bool { + fn eq(&self, _other: &Self) -> bool { false } } @@ -77,7 +73,7 @@ impl RFunction { pub fn run(&self, info: &GSInfo) -> VData { self.statement.run(info) } - pub fn out(&self, input_types: &Vec, info: &GlobalScriptInfo) -> Option { + pub fn out_by_map(&self, input_types: &Vec, info: &GlobalScriptInfo) -> Option { // NOTE: This can ONLY use self.out_map, because it's used by the VSingleType.fits_in method. let mut empty = true; let out = self @@ -101,15 +97,30 @@ impl RFunction { Some(out) } } - pub fn out_all(&self, info: &GlobalScriptInfo) -> VType { + pub fn out_all_by_map(&self, info: &GlobalScriptInfo) -> VType { // self.statement.out(info) self.out_map.iter().fold(VType::empty(), |mut t, (_, v)| { t.add_typesr(v, info); t }) } - pub fn in_types(&self) -> &Vec { - &self.input_types + pub fn out_by_statement(&self, input_types: &Vec, info: &GlobalScriptInfo) -> VType { + let mut actual = Vec::with_capacity(self.inputs.len()); + // simulate these variable types + for (fn_input, c_type) in self.inputs.iter().zip(input_types.iter()) { + actual.push(std::mem::replace( + &mut fn_input.lock().unwrap().1, + c_type.clone(), + )); + } + // not get the return type if these were the actual types + let out = self.statement.out(info); + // reset + for (fn_input, actual) in self.inputs.iter().zip(actual) { + fn_input.lock().unwrap().1 = actual; + } + // return + out } } @@ -124,18 +135,16 @@ pub struct RStatement { impl RStatement { pub fn run(&self, info: &GSInfo) -> VData { let out = self.statement.run(info); - let mut o = if let Some((v, is_init)) = &self.output_to { - 'init: { - // // assigns a new VData to the variable's Arc>, so that threads which have captured the variable at some point - // // won't be updated with its new value (is_init is set to true for initializations, such as in a loop - this can happen multiple times, but each should be its own variable with the same name) - // if *is_init && *derefs == 0 { - // Self::assign_to(out, v.run(info), info); - // break 'init; - // } - let mut val = v.run(info); - out.assign_to(val, info); - // val.assign(out); - } + let mut o = if let Some((v, _is_init)) = &self.output_to { + // // assigns a new VData to the variable's Arc>, so that threads which have captured the variable at some point + // // won't be updated with its new value (is_init is set to true for initializations, such as in a loop - this can happen multiple times, but each should be its own variable with the same name) + // if *is_init && *derefs == 0 { + // Self::assign_to(out, v.run(info), info); + // break 'init; + // } + let val = v.run(info); + out.assign_to(val, info); + // val.assign(out); VDataEnum::Tuple(vec![]).to() } else { out @@ -226,7 +235,7 @@ impl RStatementEnum { Self::For(v, c, b) => { // matching values also break with value from a for loop. let vv = v.run(info); - let mut in_loop = |c: VData| { + let in_loop = |c: VData| { c.assign_to(vv.clone_mut(), info); b.run(info) }; @@ -270,7 +279,7 @@ impl RStatementEnum { break; } }, - VDataEnum::Reference(r) => return None, + VDataEnum::Reference(_r) => return None, _ => unreachable!(), } Some(oval) @@ -355,7 +364,7 @@ impl RStatementEnum { } } Self::FunctionCall(f, args) => f - .out(&args.iter().map(|v| v.out(info)).collect(), info) + .out_by_map(&args.iter().map(|v| v.out(info)).collect(), info) .expect("invalid args for function -> can't determine output type"), Self::LibFunctionCall(.., out) => out.clone(), Self::Block(b) => b.out(info), @@ -379,13 +388,13 @@ impl RStatementEnum { } Self::Switch(switch_on, cases, force) => { let switch_on = switch_on.out(info).types; - let mut might_return_empty = switch_on.is_empty(); + let _might_return_empty = switch_on.is_empty(); let mut out = if *force { VType::empty() } else { VSingleType::Tuple(vec![]).to() }; - for switch_on in switch_on { + for _switch_on in switch_on { for (_on_type, _assign_to, case) in cases.iter() { out.add_types(case.out(info), info); } @@ -423,7 +432,7 @@ impl RStatementEnum { pub struct RScript { main: RFunction, - info: GSInfo, + pub info: GSInfo, } impl RScript { pub fn new(main: RFunction, info: GSInfo) -> Result { @@ -432,20 +441,8 @@ impl RScript { } Ok(Self { main, info }) } - pub fn run(&self, args: Vec) -> VData { - let mut vars = vec![]; - vars.push( - VDataEnum::List( - VSingleType::String.into(), - args.into_iter() - .map(|v| VDataEnum::String(v).to()) - .collect(), - ) - .to(), - ); + pub fn run(&self, args: Vec) -> VData { + self.main.inputs[0].lock().unwrap().0 = VDataEnum::List(VSingleType::Any.into(), args).to(); self.main.run(&self.info) } - pub fn info(&self) -> &GSInfo { - &self.info - } } diff --git a/mers/src/lang/fmtgs.rs b/mers/src/lang/fmtgs.rs index 28eea1a..f1cf460 100644 --- a/mers/src/lang/fmtgs.rs +++ b/mers/src/lang/fmtgs.rs @@ -5,7 +5,7 @@ use super::global_info::{ColorFormatMode, ColorFormatter, GlobalScriptInfo}; use colorize::AnsiColor; pub enum Color { - Keep, + // Keep, Grey, Red, Yellow, @@ -17,7 +17,7 @@ pub enum Color { impl Color { pub fn colorize(&self, s: String) -> String { match self { - Self::Keep => s, + // Self::Keep => s, Self::Grey => s.grey().to_string(), Self::Red => s.red().to_string(), Self::Yellow => s.yellow().to_string(), @@ -72,7 +72,7 @@ impl FormatInfo { pub fn go_shallower(&mut self) { self.depth -= 1; } - pub fn variable_ref_symbol(&self, info: Option<&GlobalScriptInfo>, s: String) -> String { + pub fn variable_ref_symbol(&self, _info: Option<&GlobalScriptInfo>, s: String) -> String { s } pub fn variable(&self, info: Option<&GlobalScriptInfo>, s: String) -> String { diff --git a/mers/src/lang/global_info.rs b/mers/src/lang/global_info.rs index f8fd354..2646233 100755 --- a/mers/src/lang/global_info.rs +++ b/mers/src/lang/global_info.rs @@ -1,23 +1,19 @@ use std::{ collections::HashMap, - default, fmt::Display, sync::{Arc, Mutex}, }; -use crate::libs; - use super::{ builtins, fmtgs::Color, - val_data::VDataEnum, val_type::{VSingleType, VType}, }; pub type GSInfo = Arc; pub struct GlobalScriptInfo { - pub libs: Vec, + pub libs: Vec, pub lib_fns: HashMap, pub enum_variants: HashMap, @@ -121,7 +117,6 @@ pub struct Logger { pub after_parse: LogKind, - pub vdata_clone: LogKind, pub vtype_fits_in: LogKind, pub vsingletype_fits_in: LogKind, } @@ -130,7 +125,6 @@ impl Logger { Self { logs: Arc::new(Mutex::new(vec![])), after_parse: Default::default(), - vdata_clone: Default::default(), vtype_fits_in: Default::default(), vsingletype_fits_in: Default::default(), } @@ -140,7 +134,6 @@ impl Logger { #[derive(Debug)] pub enum LogMsg { AfterParse(String), - VDataClone(Option, VDataEnum, usize, usize), VTypeFitsIn(VType, VType, Vec), VSingleTypeFitsIn(VSingleType, VSingleType, bool), } @@ -148,7 +141,6 @@ impl Logger { pub fn log(&self, msg: LogMsg) { let kind = match msg { LogMsg::AfterParse(..) => &self.after_parse, - LogMsg::VDataClone(..) => &self.vdata_clone, LogMsg::VTypeFitsIn(..) => &self.vtype_fits_in, LogMsg::VSingleTypeFitsIn(..) => &self.vsingletype_fits_in, }; @@ -168,17 +160,6 @@ impl Display for LogMsg { Self::AfterParse(code) => { write!(f, "AfterParse :: {code}") } - Self::VDataClone(varname, data, src_addr, new_addr) => { - write!( - f, - "VDataClone ::::\n{data} ({}{src_addr} -> {new_addr})", - if let Some(v) = varname { - format!("{v} | ") - } else { - String::new() - } - ) - } Self::VTypeFitsIn(a, b, no) => write!(f, "VTypeFitsIn :: {a} in {b} ? -> {no:?}"), Self::VSingleTypeFitsIn(a, b, fits) => { write!(f, "VSingleTypeFitsIn :: {a} in {b} ? -> {fits}") diff --git a/mers/src/lang/to_runnable.rs b/mers/src/lang/to_runnable.rs index a67810b..fe5078e 100755 --- a/mers/src/lang/to_runnable.rs +++ b/mers/src/lang/to_runnable.rs @@ -1,20 +1,14 @@ use core::panic; use std::{ collections::HashMap, - eprintln, fmt::{Debug, Display}, sync::{Arc, Mutex}, - time::Duration, }; -use crate::{ - lang::{ - builtins, - global_info::GlobalScriptInfo, - val_data::{VData, VDataEnum}, - val_type::{VSingleType, VType}, - }, - libs, +use crate::lang::{ + global_info::GlobalScriptInfo, + val_data::{VData, VDataEnum}, + val_type::{VSingleType, VType}, }; use super::{ @@ -84,12 +78,12 @@ impl FormatGs for ToRunnableError { write!(f, "Cannot dereference type ")?; og_type.fmtgs(f, info, form, file)?; write!(f, " {derefs_wanted} times (stopped at ")?; - last_valid_type.fmtgs(f, info, form, file); + last_valid_type.fmtgs(f, info, form, file)?; write!(f, ")")?; Ok(()) } Self::FunctionWrongArgs(fn_name, possible_fns, given_types) => { - write!(f, "Wrong args for function \"{fn_name}\": Found ("); + write!(f, "Wrong args for function \"{fn_name}\": Found (")?; for (i, t) in given_types.iter().enumerate() { if i > 0 { write!(f, ", ")?; @@ -277,25 +271,7 @@ fn function( } } } - // let out = o.out(¤t_types, ginfo).expect("invalid args????"); - let out = { - let mut actual = Vec::with_capacity(o.inputs.len()); - // simulate these variable types - for (fn_input, c_type) in o.inputs.iter().zip(current_types.iter()) { - actual.push(std::mem::replace( - &mut fn_input.lock().unwrap().1, - c_type.clone(), - )); - } - // not get the return type if these were the actual types - let out = o.statement.out(ginfo); - // reset - for (fn_input, actual) in o.inputs.iter().zip(actual) { - std::mem::replace(&mut fn_input.lock().unwrap().1, actual); - } - // return - out - }; + let out = o.out_by_statement(¤t_types, &ginfo); map.push((current_types, out)); if was_last { break map; @@ -627,11 +603,11 @@ fn statement_adv( RStatementEnum::Switch(switch_on, ncases, *force).to() } SStatementEnum::Match(cases) => { - let mut ncases: Vec<(RStatement, RStatement, RStatement)> = + let _ncases: Vec<(RStatement, RStatement, RStatement)> = Vec::with_capacity(cases.len()); let mut ncases = Vec::with_capacity(cases.len()); let mut out_type = VType::empty(); - let mut may_not_match = true; + let may_not_match = true; for (condition, assign_to, action) in cases.iter() { let mut linfo = linfo.clone(); let condition = statement(condition, ginfo, &mut linfo)?; diff --git a/mers/src/lang/val_data.rs b/mers/src/lang/val_data.rs index 4d171cb..2d7a1fc 100755 --- a/mers/src/lang/val_data.rs +++ b/mers/src/lang/val_data.rs @@ -1,10 +1,8 @@ use std::{ fmt::{self, Debug, Display, Formatter}, - ops::Deref, - sync::{Arc, Mutex, MutexGuard}, + sync::{Arc, Mutex}, }; -use super::global_info::LogMsg; use super::{ code_runnable::RFunction, fmtgs::FormatGs, @@ -68,14 +66,14 @@ impl VData { pub fn clone_data(&self) -> Self { // TODO! implement CopyOnWrite. For now, just always copy. This also prevents mut references not existing since in ::Dat(cloned, _), cloned will always stay 0. return self.operate_on_data_immut(|v| v.clone()).to(); - match &mut *self.0.lock().unwrap() { - VDataInner::Data(cloned, _data) => { - *cloned += 1; - VDataInner::ClonedFrom(self.clone_arc()).to() - } - VDataInner::Mut(inner) => inner.lock().unwrap().clone_data(), - VDataInner::ClonedFrom(inner) => inner.clone_data(), - } + // match &mut *self.0.lock().unwrap() { + // VDataInner::Data(cloned, _data) => { + // *cloned += 1; + // VDataInner::ClonedFrom(self.clone_arc()).to() + // } + // VDataInner::Mut(inner) => inner.lock().unwrap().clone_data(), + // VDataInner::ClonedFrom(inner) => inner.clone_data(), + // } } /// clones self, returning a new instance of self that will always yield the same data as self, so that changes done to either are shared between both. pub fn clone_mut(&self) -> Self { @@ -87,7 +85,7 @@ impl VData { #[cfg(debug_assertions)] return Self(Arc::clone(&self.0), self.1.clone()); } - pub fn operate_on_data_immut(&self, mut func: F) -> O + pub fn operate_on_data_immut(&self, func: F) -> O where F: FnOnce(&VDataEnum) -> O, { @@ -100,7 +98,7 @@ impl VData { /// runs func on the underlying data. /// attempts to get a mutable reference to the data. if this fails, it will (partially) clone the data, then point the VData to the new data, /// so that other VDatas pointing to the same original data aren't changed. - pub fn operate_on_data_mut(&mut self, mut func: F) -> O + pub fn operate_on_data_mut(&mut self, func: F) -> O where F: FnOnce(&mut VDataEnum) -> O, { @@ -170,7 +168,7 @@ impl VData { impl Drop for VDataInner { fn drop(&mut self) { if let Self::ClonedFrom(origin) = self { - if let Self::Data(ref_count, _data) = &mut *origin.0.lock().unwrap() { + if let Self::Data(_ref_count, _data) = &mut *origin.0.lock().unwrap() { // *ref_count = ref_count.saturating_sub(1); } } @@ -340,7 +338,7 @@ impl VDataEnum { pub fn noenum(&self) -> Option { match self { Self::EnumVariant(_, v) => Some(v.clone_data()), - v => None, + _v => None, } } pub fn get(&self, i: usize) -> Option { @@ -372,19 +370,12 @@ impl VDataEnum { | Self::Function(..) | Self::Thread(..) => None, // TODO: String - Self::String(s) => None, + Self::String(_s) => None, Self::Tuple(v) | Self::List(_, v) => v.get(i).map(|v| v.clone_mut()), Self::Reference(r) => r.get_ref(i), Self::EnumVariant(_, v) => v.get_ref(i), } } - pub fn matches_ref_bool(&self) -> bool { - match self { - VDataEnum::Tuple(v) => !v.is_empty(), - VDataEnum::Bool(false) => false, - _ => true, - } - } /// Some(None) => matches with self pub fn matches(&self) -> Option> { match self { @@ -397,7 +388,7 @@ impl VDataEnum { } } VDataEnum::EnumVariant(..) => None, - other => Some(None), + _other => Some(None), } } } @@ -487,7 +478,7 @@ pub mod thread { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &*self.lock() { VDataThreadEnum::Running(_) => write!(f, "(thread running)"), - VDataThreadEnum::Finished(v) => write!(f, "(thread finished)"), + VDataThreadEnum::Finished(_v) => write!(f, "(thread finished)"), } } } @@ -553,7 +544,7 @@ impl FormatGs for VDataEnum { } Self::List(_t, v) => { write!(f, "[")?; - for (i, v) in v.iter().enumerate() { + for (_i, v) in v.iter().enumerate() { v.fmtgs(f, info, form, file)?; write!(f, " ")?; } diff --git a/mers/src/lang/val_type.rs b/mers/src/lang/val_type.rs index 51f21b9..1b9e3aa 100755 --- a/mers/src/lang/val_type.rs +++ b/mers/src/lang/val_type.rs @@ -1,14 +1,12 @@ use std::{ collections::HashMap, fmt::{self, Debug, Display, Formatter}, - ops::BitOr, - sync::Arc, }; use super::{ code_runnable::{RFunction, RStatementEnum}, fmtgs::FormatGs, - global_info::{self, GSInfo, GlobalScriptInfo}, + global_info::{GSInfo, GlobalScriptInfo}, val_data::VDataEnum, }; @@ -173,7 +171,7 @@ impl VType { Some(out) } pub fn reference(&self) -> Self { - let mut out = Self::empty(); + let _out = Self::empty(); Self { types: self .types @@ -474,7 +472,7 @@ impl VSingleType { }; for (ins, out) in b { // try everything that would be valid for b - if let Some(v) = af.out(ins, info) { + if let Some(v) = af.out_by_map(ins, info) { if !v.fits_in(out, info).is_empty() { // found something that's valid for both, but a returns something that doesn't fit in what b would have returned -> a doesn't fit. break 'fnt false; @@ -572,7 +570,7 @@ impl FormatGs for VSingleType { write!(f, "(")?; for i in inputs { i.fmtgs(f, info, form, file)?; - write!(f, " "); + write!(f, " ")?; } output.fmtgs(f, info, form, file)?; write!(f, ")")?; diff --git a/mers/src/lib.rs b/mers/src/lib.rs index 1c00792..211eb28 100755 --- a/mers/src/lib.rs +++ b/mers/src/lib.rs @@ -1,12 +1,12 @@ +mod inlib; mod lang; mod libs; mod parsing; +mod pathutil; +pub use inlib::MyLib; pub use lang::{global_info::GlobalScriptInfo, val_data::*, val_type::*}; -pub use libs::{ - comms::{ByteData, ByteDataA, Message, RespondableMessage}, - inlib::MyLib, -}; +pub use libs::comms::{ByteData, ByteDataA, Message, RespondableMessage}; pub use parsing::*; pub mod prelude { diff --git a/mers/src/libs/comms.rs b/mers/src/libs/comms.rs index 2a576ce..bddb48b 100644 --- a/mers/src/libs/comms.rs +++ b/mers/src/libs/comms.rs @@ -42,10 +42,10 @@ impl ByteData for Message { where R: std::io::Read, { - let mut type_id = u32::from_byte_data(data)?; + let type_id = u32::from_byte_data(data)?; Ok(match type_id { 0 => Self::RunFunction(ByteData::from_byte_data(data)?), - other => unreachable!("read unknown type_id byte for message!"), + _other => unreachable!("read unknown type_id byte for message!"), }) } } @@ -270,7 +270,7 @@ impl ByteData for String { { let len = ByteData::from_byte_data(data)?; let mut buf = vec![0; len]; - data.read_exact(buf.as_mut_slice()); + data.read_exact(buf.as_mut_slice())?; let str = String::from_utf8(buf).unwrap(); Ok(str) } @@ -503,7 +503,7 @@ impl ByteDataA for VDataEnum { // TODO? Self::Function(_) => vec.push(b'F'), Self::Thread(..) => vec.push(b'T'), - Self::Reference(r) => vec.push(b'R'), + Self::Reference(_r) => vec.push(b'R'), Self::EnumVariant(enum_id, inner) => { vec.push(b'E'); enum_id.as_byte_data(vec); diff --git a/mers/src/libs/mod.rs b/mers/src/libs/mod.rs index 739eeb6..2b2a2d7 100755 --- a/mers/src/libs/mod.rs +++ b/mers/src/libs/mod.rs @@ -1,26 +1,17 @@ pub mod comms; -pub mod inlib; -pub mod path; use std::{ collections::HashMap, - io::{self, BufRead, BufReader, Read, Write}, - path::PathBuf, + io::{self, BufReader, Write}, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, sync::{Arc, Mutex}, }; -use crate::{ - lang::{ - global_info::GlobalScriptInfo, - val_data::{VData, VDataEnum}, - val_type::VType, - }, - libs::comms::{ByteData, ByteDataA}, - parsing::{file::File, parse}, +use crate::lang::{ + global_info::GlobalScriptInfo, to_runnable::ToRunnableError, val_data::VData, val_type::VType, }; -use self::comms::{MessageResponse, RespondableMessage}; +use self::comms::{ByteData, ByteDataA, RespondableMessage}; // Libraries are processes that communicate via stdout/stdin. @@ -59,6 +50,8 @@ pub type LibInitReq<'a> = ( ); /// Sent by mers to finish initializing a library. /// [enum variants] +// used by crate::inlib +#[allow(unused)] pub type LibInitInfo = Vec<(String, usize)>; pub type LibInitInfoRef<'a> = Vec<(&'a String, &'a usize)>; @@ -93,9 +86,13 @@ impl Lib { for (_name, func) in registered_fns.iter_mut() { for (args, out) in func.iter_mut() { for t in args.iter_mut() { - crate::lang::to_runnable::stypes(t, &mut ginfo); + if let Err(e) = crate::lang::to_runnable::stypes(t, &mut ginfo) { + return Err(LaunchError::ErrorAddingEnumsOrTypes(e)); + } + } + if let Err(e) = crate::lang::to_runnable::stypes(out, &mut ginfo) { + return Err(LaunchError::ErrorAddingEnumsOrTypes(e)); } - crate::lang::to_runnable::stypes(out, &mut ginfo); } } for (name, id) in ginfo.enum_variants { @@ -104,13 +101,17 @@ impl Lib { } } let si: LibInitInfoRef = enum_variants.iter().collect(); - stdin.write(si.as_byte_data_vec().as_slice()); - stdin.flush(); + if let Err(e) = stdin.write_all(si.as_byte_data_vec().as_slice()) { + return Err(LaunchError::StdioError(e)); + }; + if let Err(e) = stdin.flush() { + return Err(LaunchError::StdioError(e)); + }; let (task_sender, recv) = std::sync::mpsc::channel::<( u128, Box) + Send>, )>(); - let stdout_reader = std::thread::spawn(move || { + let _stdout_reader = std::thread::spawn(move || { let dur = std::time::Duration::from_millis(20); let mut pending = HashMap::new(); loop { @@ -192,11 +193,11 @@ impl Lib { )) .unwrap(); // id - type_id - message - stdin.write(id.as_byte_data_vec().as_slice()).unwrap(); + stdin.write_all(id.as_byte_data_vec().as_slice()).unwrap(); stdin - .write(msg.msgtype_id().as_byte_data_vec().as_slice()) + .write_all(msg.msgtype_id().as_byte_data_vec().as_slice()) .unwrap(); - stdin.write(msg.as_byte_data_vec().as_slice()).unwrap(); + stdin.write_all(msg.as_byte_data_vec().as_slice()).unwrap(); stdin.flush().unwrap(); *id = id.wrapping_add(1); recv @@ -209,12 +210,18 @@ impl Lib { pub enum LaunchError { NoStdio, CouldNotSpawnProcess(io::Error), + StdioError(io::Error), + ErrorAddingEnumsOrTypes(ToRunnableError), } impl std::fmt::Display for LaunchError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::NoStdio => write!(f, "couldn't get stdio (stdin/stdout) from child process."), Self::CouldNotSpawnProcess(e) => write!(f, "couldn't spawn child process: {e}."), + Self::StdioError(e) => write!(f, "error from stdio: {e}"), + Self::ErrorAddingEnumsOrTypes(e) => { + write!(f, "error adding enums or types from library: {e}.") + } } } } diff --git a/mers/src/main.rs b/mers/src/main.rs index 766340d..8b3df73 100755 --- a/mers/src/main.rs +++ b/mers/src/main.rs @@ -1,9 +1,7 @@ -use std::{fs, time::Instant}; - use lang::global_info::ColorFormatMode; use lang::global_info::GlobalScriptInfo; use lang::global_info::LogKind; -use notify::Watcher as FsWatcher; +use lang::val_data::VDataEnum; use crate::lang::fmtgs::FormatGs; @@ -13,6 +11,7 @@ mod libs; #[cfg(feature = "nushell_plugin")] mod nushell_plugin; mod parsing; +mod pathutil; mod tutor; fn main() { @@ -113,7 +112,6 @@ fn normal_main() { log: true, } } - info.log.vdata_clone = f(); info.log.vtype_fits_in = f(); info.log.vsingletype_fits_in = f(); } else { @@ -144,7 +142,6 @@ fn normal_main() { None => (verbose_arg, None), }; match arg { - "vdata_clone" => info.log.vdata_clone = kind(val), "vtype_fits_in" => info.log.vtype_fits_in = kind(val), "vsingletype_fits_in" => info.log.vsingletype_fits_in = kind(val), _ => eprintln!("Warn: -v+ unknown arg '{arg}'."), @@ -157,6 +154,7 @@ fn normal_main() { _ => { // basic: open file and watch for fs changes interactive_mode::fs_watcher::playground(interactive_use_new_terminal) + .unwrap() } }; return; @@ -194,7 +192,12 @@ fn normal_main() { match parsing::parse::parse_custom_info(&mut file, info) { Ok(script) => { if run { - script.run(std::env::args().skip(args_to_skip).collect()); + script.run( + std::env::args() + .skip(args_to_skip) + .map(|v| VDataEnum::String(v).to()) + .collect(), + ); } } Err(e) => { diff --git a/mers/src/nushell_plugin.rs b/mers/src/nushell_plugin.rs index b830020..95c4a06 100755 --- a/mers/src/nushell_plugin.rs +++ b/mers/src/nushell_plugin.rs @@ -1,12 +1,14 @@ use std::{fs, path::PathBuf}; use nu_plugin::{serve_plugin, MsgPackSerializer, Plugin}; -use nu_protocol::{PluginExample, PluginSignature, ShellError, Span, Spanned, SyntaxShape, Value}; +use nu_protocol::{PluginSignature, ShellError, Span, SyntaxShape, Value}; use crate::{ lang::{ + fmtgs::FormatGs, global_info::GlobalScriptInfo, val_data::{VData, VDataEnum}, + val_type::VType, }, parsing, }; @@ -27,7 +29,24 @@ impl Plugin for MersNuPlugin { ) .optional( "args", - SyntaxShape::List(Box::new(SyntaxShape::String)), + SyntaxShape::List(Box::new(SyntaxShape::OneOf(vec![ + SyntaxShape::Boolean, + SyntaxShape::Int, + SyntaxShape::Decimal, + SyntaxShape::String, + SyntaxShape::List(Box::new(SyntaxShape::OneOf(vec![ + SyntaxShape::Boolean, + SyntaxShape::Int, + SyntaxShape::Decimal, + SyntaxShape::String, + SyntaxShape::List(Box::new(SyntaxShape::OneOf(vec![ + SyntaxShape::Boolean, + SyntaxShape::Int, + SyntaxShape::Decimal, + SyntaxShape::String, + ]))), + ]))), + ]))), "the arguments passed to the mers program. defaults to an empty list.", ) .switch( @@ -38,9 +57,9 @@ impl Plugin for MersNuPlugin { } fn run( &mut self, - name: &str, + _name: &str, call: &nu_plugin::EvaluatedCall, - input: &nu_protocol::Value, + _input: &nu_protocol::Value, ) -> Result { // no need to 'match name {...}' because we only register mers-nu and nothing else. let source: String = call.req(0)?; @@ -52,7 +71,7 @@ impl Plugin for MersNuPlugin { parsing::file::File::new( match fs::read_to_string(&source) { Ok(v) => v, - Err(e) => { + Err(_e) => { return Ok(Value::Error { error: Box::new(ShellError::FileNotFound(source_span)), }) @@ -64,36 +83,62 @@ impl Plugin for MersNuPlugin { Ok(match parsing::parse::parse(&mut file) { Ok(code) => { let args = match call.opt(1)? { - Some(v) => v, + Some(v) => { + fn to_mers_val(v: Vec, info: &GlobalScriptInfo) -> Vec { + v.into_iter() + .map(|v| { + match v { + Value::Bool { val, .. } => VDataEnum::Bool(val), + Value::Int { val, .. } => VDataEnum::Int(val as _), + Value::Float { val, .. } => VDataEnum::Float(val), + Value::String { val, .. } => VDataEnum::String(val), + Value::List { vals, .. } => { + let mut t = VType::empty(); + let mut vs = Vec::with_capacity(vals.len()); + for v in to_mers_val(vals, info) { + t.add_types(v.out(), info); + vs.push(v); + } + VDataEnum::List(t, vs) + } + _ => unreachable!("invalid arg type"), + } + .to() + }) + .collect() + } + if let Value::List { vals, .. } = v { + to_mers_val(vals, &code.info) + } else { + unreachable!("args not a list") + } + } _ => vec![], }; - fn to_nu_val(val: VData, info: &GlobalScriptInfo) -> Value { + fn to_nu_val(val: &VData, info: &GlobalScriptInfo) -> Value { let span = Span::unknown(); - match val.data { - VDataEnum::Bool(val) => Value::Bool { val, span }, + val.operate_on_data_immut(|val| match val { + VDataEnum::Bool(val) => Value::Bool { val: *val, span }, VDataEnum::Int(val) => Value::Int { - val: val as _, + val: *val as _, + span, + }, + VDataEnum::Float(val) => Value::Float { val: *val, span }, + VDataEnum::String(val) => Value::String { + val: val.to_owned(), span, }, - VDataEnum::Float(val) => Value::Float { val, span }, - VDataEnum::String(val) => Value::String { val, span }, VDataEnum::Tuple(vals) | VDataEnum::List(_, vals) => Value::List { - vals: vals.into_iter().map(|v| to_nu_val(v, info)).collect(), + vals: vals.iter().map(|v| to_nu_val(v, info)).collect(), span, }, - VDataEnum::Reference(r) => to_nu_val( - std::mem::replace( - &mut *r.lock().unwrap(), - VDataEnum::Tuple(vec![]).to(), - ), - info, - ), + VDataEnum::Reference(r) => to_nu_val(r, info), VDataEnum::EnumVariant(variant, val) => { let name = info .enum_variants .iter() .find_map(|(name, id)| { - if *id == variant { + if *id == *variant { Some(name.to_owned()) } else { None @@ -107,16 +152,16 @@ impl Plugin for MersNuPlugin { val: name, span: span, }, - to_nu_val(*val, info), + to_nu_val(val, info), ], span, } } - VDataEnum::Function(func) => Value::Nothing { span }, - VDataEnum::Thread(t, _) => to_nu_val(t.get(), info), - } + VDataEnum::Function(_func) => Value::Nothing { span }, + VDataEnum::Thread(t, _) => to_nu_val(&t.get(), info), + }) } - to_nu_val(code.run(args), code.info().as_ref()) + to_nu_val(&code.run(args), &code.info) } Err(e) => Value::Error { error: Box::new(ShellError::IncorrectValue { diff --git a/mers/src/parsing/parse.rs b/mers/src/parsing/parse.rs index 3fb8e17..533ca26 100755 --- a/mers/src/parsing/parse.rs +++ b/mers/src/parsing/parse.rs @@ -1,11 +1,11 @@ -use std::{fmt::Debug, process::Command, sync::Arc}; +use std::{fmt::Debug, process::Command}; use crate::{ lang::{ code_macro::MacroError, code_parsed::*, code_runnable::RScript, - fmtgs::{FormatGs, FormatWithGs}, + fmtgs::FormatGs, global_info::{GSInfo, GlobalScriptInfo}, to_runnable::{self, ToRunnableError}, val_data::VDataEnum, @@ -101,7 +101,7 @@ impl FormatGs for Error { fn fmtgs( &self, f: &mut std::fmt::Formatter, - info: Option<&GlobalScriptInfo>, + _info: Option<&GlobalScriptInfo>, form: &mut crate::lang::fmtgs::FormatInfo, file: Option<&crate::parsing::file::File>, ) -> std::fmt::Result { @@ -158,7 +158,7 @@ impl std::fmt::Display for CannotFindPathForLibrary { } pub fn parse_step_lib_paths( file: &mut File, - ginfo: &GlobalScriptInfo, + _ginfo: &GlobalScriptInfo, ) -> Result, CannotFindPathForLibrary> { let mut libs = vec![]; loop { @@ -166,13 +166,14 @@ pub fn parse_step_lib_paths( let pos = file.get_pos().clone(); let line = file.next_line(); if line.starts_with("lib ") { - let path_to_executable = match libs::path::path_from_string(&line[4..], file.path()) { - Some(v) => v, - None => return Err(CannotFindPathForLibrary(line[4..].to_string())), - }; + let path_to_executable = + match crate::pathutil::path_from_string(&line[4..], file.path(), true) { + Some(v) => v, + None => return Err(CannotFindPathForLibrary(line[4..].to_string())), + }; let mut cmd = Command::new(&path_to_executable); if let Some(parent) = path_to_executable.parent() { - cmd.current_dir(parent.clone()); + cmd.current_dir(parent); } libs.push(cmd); } else { @@ -190,7 +191,7 @@ pub fn parse_step_interpret( let o = SFunction::new( vec![( "args".to_string(), - VSingleType::List(VSingleType::String.into()).to(), + VSingleType::List(VSingleType::Any.into()).to(), )], SStatementEnum::Block(parse_block_advanced(file, Some(false), true, true, false)?).to(), ); @@ -251,12 +252,12 @@ impl FormatGs for ParseError { fn fmtgs( &self, f: &mut std::fmt::Formatter, - info: Option<&GlobalScriptInfo>, + _info: Option<&GlobalScriptInfo>, form: &mut crate::lang::fmtgs::FormatInfo, file: Option<&crate::parsing::file::File>, ) -> std::fmt::Result { self.err.fmtgs(f, self.info.as_ref(), form, file)?; - writeln!(f); + writeln!(f)?; if let Some(location_end) = self.location_end { writeln!(f, " from {} to {}", self.location, location_end)?; if let Some(file) = file { @@ -849,7 +850,7 @@ pub mod implementation { }; out.derefs = derefs; out.force_output_type = force_opt; - let err_end_of_original_statement = *file.get_pos(); + let _err_end_of_original_statement = *file.get_pos(); // special characters that can follow a statement (loop because these can be chained) loop { file.skip_whitespaces(); diff --git a/mers/src/libs/path.rs b/mers/src/pathutil.rs similarity index 60% rename from mers/src/libs/path.rs rename to mers/src/pathutil.rs index fd22e83..6129423 100755 --- a/mers/src/libs/path.rs +++ b/mers/src/pathutil.rs @@ -1,6 +1,10 @@ use std::path::PathBuf; -pub fn path_from_string(path: &str, script_path: &PathBuf) -> Option { +pub fn path_from_string( + path: &str, + script_path: &PathBuf, + fallback_to_lib_dir: bool, +) -> Option { let path = PathBuf::from(path); if path.is_absolute() { return Some(path); @@ -19,10 +23,12 @@ pub fn path_from_string(path: &str, script_path: &PathBuf) -> Option { return Some(p); } } - if let Ok(mers_lib_dir) = std::env::var("MERS_LIB_DIR") { - let p = PathBuf::from(mers_lib_dir).join(&path); - if p.exists() { - return Some(p); + if fallback_to_lib_dir { + if let Ok(mers_lib_dir) = std::env::var("MERS_LIB_DIR") { + let p = PathBuf::from(mers_lib_dir).join(&path); + if p.exists() { + return Some(p); + } } } None diff --git a/mers/src/tutor/mod.rs b/mers/src/tutor/mod.rs index 1145401..b82f026 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 std::{path::PathBuf, thread::JoinHandle}; use crate::{ - lang::{code_runnable::RScript, fmtgs::FormatGs, global_info::GSInfo, val_data::VDataEnum}, - parsing::{self, file::File, parse::ScriptError}, + lang::{code_runnable::RScript, fmtgs::FormatGs, val_data::VDataEnum}, + parsing::{self, file::File}, }; mod base_comments;