fixed warnings, cargo clippy, and mers-nu

This commit is contained in:
mark 2023-06-06 15:22:45 +02:00
parent 50e11dc967
commit 46dbb13e0f
19 changed files with 280 additions and 259 deletions

1
args.mers Normal file
View File

@ -0,0 +1 @@
args.debug()

View File

@ -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<Result<(), Message>, 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<M>
where
M: super::comms::RespondableMessage,
M: RespondableMessage,
{
pub nonconsuming: Vec<Box<dyn FnMut(&M)>>,
pub consuming: Option<Box<dyn FnMut(Respondable<M>)>>,
}
impl<M> Callback<M>
where
M: super::comms::RespondableMessage,
M: RespondableMessage,
{
pub fn empty() -> Self {
Self {

View File

@ -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")
}
}
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<RStatement>, 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 _)),

View File

@ -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<Macro, MacroError> {
}
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<RScript, MacroError> {
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)

View File

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

View File

@ -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>, 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<VType>, info: &GlobalScriptInfo) -> Option<VType> {
pub fn out_by_map(&self, input_types: &Vec<VType>, info: &GlobalScriptInfo) -> Option<VType> {
// 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<VType> {
&self.input_types
pub fn out_by_statement(&self, input_types: &Vec<VType>, 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: {
let mut o = if let Some((v, _is_init)) = &self.output_to {
// // assigns a new VData to the variable's Arc<Mutex<_>>, 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);
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<Self, ToRunnableError> {
@ -432,20 +441,8 @@ impl RScript {
}
Ok(Self { main, info })
}
pub fn run(&self, args: Vec<String>) -> 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>) -> 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
}
}

View File

@ -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 {

View File

@ -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<GlobalScriptInfo>;
pub struct GlobalScriptInfo {
pub libs: Vec<libs::Lib>,
pub libs: Vec<crate::libs::Lib>,
pub lib_fns: HashMap<String, (usize, usize)>,
pub enum_variants: HashMap<String, usize>,
@ -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<String>, VDataEnum, usize, usize),
VTypeFitsIn(VType, VType, Vec<VSingleType>),
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}")

View File

@ -1,20 +1,14 @@
use core::panic;
use std::{
collections::HashMap,
eprintln,
fmt::{Debug, Display},
sync::{Arc, Mutex},
time::Duration,
};
use crate::{
lang::{
builtins,
use crate::lang::{
global_info::GlobalScriptInfo,
val_data::{VData, VDataEnum},
val_type::{VSingleType, VType},
},
libs,
};
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(&current_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(&current_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)?;

View File

@ -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<F, O>(&self, mut func: F) -> O
pub fn operate_on_data_immut<F, O>(&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<F, O>(&mut self, mut func: F) -> O
pub fn operate_on_data_mut<F, O>(&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<VData> {
match self {
Self::EnumVariant(_, v) => Some(v.clone_data()),
v => None,
_v => None,
}
}
pub fn get(&self, i: usize) -> Option<VData> {
@ -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<Option<VData>> {
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, " ")?;
}

View File

@ -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, ")")?;

View File

@ -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 {

View File

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

View File

@ -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<dyn FnOnce(&mut BufReader<ChildStdout>) + 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}.")
}
}
}
}

View File

@ -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) => {

View File

@ -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<nu_protocol::Value, nu_plugin::LabeledError> {
// 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<Value>, info: &GlobalScriptInfo) -> Vec<VData> {
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 {

View File

@ -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<Vec<Command>, 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()) {
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();

View File

@ -1,6 +1,10 @@
use std::path::PathBuf;
pub fn path_from_string(path: &str, script_path: &PathBuf) -> Option<PathBuf> {
pub fn path_from_string(
path: &str,
script_path: &PathBuf,
fallback_to_lib_dir: bool,
) -> Option<PathBuf> {
let path = PathBuf::from(path);
if path.is_absolute() {
return Some(path);
@ -19,11 +23,13 @@ pub fn path_from_string(path: &str, script_path: &PathBuf) -> Option<PathBuf> {
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
}

View File

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