diff --git a/amogus.mers b/amogus.mers index 2f5c31a..aae534a 100644 --- a/amogus.mers +++ b/amogus.mers @@ -25,4 +25,3 @@ for word text.regex("\\S+").assume_no_enum() words = rnd() sleep(0.75) } -println(" ~ ~ ~ ~ ~ ~ ~ ~ ~ ~") diff --git a/get_ref.mers b/get_ref.mers index f184436..03d1fe1 100644 --- a/get_ref.mers +++ b/get_ref.mers @@ -6,5 +6,10 @@ list = [1 2 3 4 5 6 7 8 9 ...] // second.debug() &list.get_ref(2).assume1() = 24 +should_not_be_changeable = &list.get(3).assume1() +should_not_be_changeable = 24 + +if list.get(2) != [24] println("[!!] list.get(2) != 24 (was {0})".format(list.get(2).to_string())) +if list.get(3) == [24] println("[!!] list.get(3) == 24") list.debug() diff --git a/http.mers b/http.mers index 954b6cf..acc4a11 100644 --- a/http.mers +++ b/http.mers @@ -6,7 +6,7 @@ t = thread(() { println("got words from word list!") }) -sleep(0.5) +sleep(0.1) // this will finish before the thread does. http_get("https:\//github.com/").assume_no_enum() diff --git a/mers/a.mers b/mers/a.mers deleted file mode 100644 index 0edeae7..0000000 --- a/mers/a.mers +++ /dev/null @@ -1,4 +0,0 @@ -a = 1 -b = 2 -a.debug() -b.debug() diff --git a/mers/c.mers b/mers/c.mers new file mode 100644 index 0000000..32caa97 --- /dev/null +++ b/mers/c.mers @@ -0,0 +1,4 @@ +list = [1 ...] +b = list +&list.pop() +list \ No newline at end of file diff --git a/mers/src/script/builtins.rs b/mers/src/lang/builtins.rs similarity index 54% rename from mers/src/script/builtins.rs rename to mers/src/lang/builtins.rs index f48ad33..cc416b2 100755 --- a/mers/src/script/builtins.rs +++ b/mers/src/lang/builtins.rs @@ -64,6 +64,7 @@ pub enum BuiltinFunction { Mod, Pow, Eq, + Ne, Gt, Lt, Gtoe, @@ -128,6 +129,7 @@ impl BuiltinFunction { "mod" => Self::Mod, "pow" => Self::Pow, "eq" => Self::Eq, + "ne" => Self::Ne, "lt" => Self::Lt, "gt" => Self::Gt, "ltoe" => Self::Ltoe, @@ -330,7 +332,7 @@ impl BuiltinFunction { false } } - Self::Eq => input.len() == 2, + Self::Eq | Self::Ne => input.len() == 2, Self::Add => { input.len() == 2 && { let num = VType { @@ -728,7 +730,9 @@ impl BuiltinFunction { unreachable!("called add/sub/mul/div/mod/pow with args != 2") } } - Self::Eq | Self::Lt | Self::Gt | Self::Ltoe | Self::Gtoe => VSingleType::Bool.to(), + Self::Eq | Self::Ne | Self::Lt | Self::Gt | Self::Ltoe | Self::Gtoe => { + VSingleType::Bool.to() + } Self::Push | Self::Insert => VSingleType::Tuple(vec![]).into(), Self::Len => VSingleType::Int.into(), Self::Contains | Self::StartsWith | Self::EndsWith => VSingleType::Bool.into(), @@ -748,95 +752,99 @@ impl BuiltinFunction { }, } } - pub fn run(&self, args: &Vec, vars: &mut Vec, info: &GSInfo) -> VData { + pub fn run(&self, args: &Vec, info: &GSInfo) -> VData { match self { Self::Assume1 => { - let mut a0 = args[0].run(vars, info); - a0.make_mut(); - let o = match &mut a0.data.lock().unwrap().0 { - VDataEnum::Tuple(v) => Some({ - if let Some(v) = v.pop() { - v + let mut 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) { + Ok(Some(v.clone_data())) } else { - let msg = if args.len() > 1 { - let a1 = args[1].run(vars, info); - let a1 = a1.data(); - if let VDataEnum::String(v) = &a1.0 { + Err(()) + } + } else { + Ok(None) + } + }) { + Ok(Some(v)) => v, + Ok(None) => a0, + Err(()) => { + let msg = if args.len() > 1 { + args[1].run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(v) = v { Some(v.to_owned()) } else { None } - } else { - None - }; - if let Some(m) = msg { - panic!("ASSUMPTION FAILED: assume1 :: {m}"); - } else { - panic!("ASSUMPTION FAILED: assume1"); - } + }) + } else { + None + }; + if let Some(m) = msg { + panic!("ASSUMPTION FAILED: assume1 :: {m}"); + } else { + panic!("ASSUMPTION FAILED: assume1"); } - }), - _ => None, - }; - if let Some(o) = o { - o - } else { - a0 + } } } Self::AssumeNoEnum => { - let msg = if args.len() > 1 { - if let VDataEnum::String(v) = args[1].run(vars, info).inner() { - Some(v.to_owned()) + let a0 = args[0].run(info); + let was_ok = a0.operate_on_data_immut(|v| match v { + VDataEnum::EnumVariant(..) => false, + _ => true, + }); + if was_ok { + a0 + } else { + let msg = if args.len() > 1 { + args[1].run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(v) = v { + Some(v.to_owned()) + } else { + None + } + }) } else { None - } - } else { - None - }; - let a0 = args[0].run(vars, info); - let a0d = a0.data(); - match &a0d.0 { - VDataEnum::EnumVariant(..) => { - drop(a0d); - panic!( - "ASSUMPTION FAILED: assume_no_enum :: found {}{}", - a0.gsi(info.clone()), - if let Some(m) = msg { - format!(" :: {m}") - } else { - String::new() - } - ) - } - _ => { - drop(a0d); - a0 - } + }; + panic!( + "ASSUMPTION FAILED: assume_no_enum :: found {}{}", + a0.gsi(info.clone()), + if let Some(m) = msg { + format!(" :: {m}") + } else { + String::new() + } + ); } } - Self::NoEnum => args[0].run(vars, info).noenum(), - Self::Matches => match args[0].run(vars, info).inner().matches() { + Self::NoEnum => args[0].run(info).noenum(), + Self::Matches => match args[0].run(info).matches() { Some(v) => VDataEnum::Tuple(vec![v]).to(), None => VDataEnum::Tuple(vec![]).to(), }, - Self::Clone => { - if let VDataEnum::Reference(r) = &args[0].run(vars, info).data().0 { - r.clone() + Self::Clone => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::Reference(r) = v { + r.clone_data() } else { unreachable!() } - } - BuiltinFunction::Print => { - if let VDataEnum::String(arg) = &args[0].run(vars, info).data().0 { + }), + BuiltinFunction::Print => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(arg) = v { + #[cfg(not(feature = "nushell_plugin"))] print!("{}", arg); + #[cfg(feature = "nushell_plugin")] + eprint!("{}", arg); VDataEnum::Tuple(vec![]).to() } else { unreachable!("print function called with non-string arg") } - } - BuiltinFunction::Println => { - if let VDataEnum::String(arg) = &args[0].run(vars, info).data().0 { + }), + BuiltinFunction::Println => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(arg) = v { #[cfg(not(feature = "nushell_plugin"))] println!("{}", arg); #[cfg(feature = "nushell_plugin")] @@ -845,9 +853,9 @@ impl BuiltinFunction { } else { unreachable!() } - } + }), BuiltinFunction::Debug => { - let val = args[0].run(vars, info); + let val = args[0].run(info); #[cfg(not(feature = "nushell_plugin"))] println!( "{} :: {} :: {}", @@ -870,209 +878,170 @@ impl BuiltinFunction { VDataEnum::String(line.trim_end_matches(['\n', '\r']).to_string()).to() } BuiltinFunction::ToString => { - VDataEnum::String(args[0].run(vars, info).gsi(info.clone()).to_string()).to() + VDataEnum::String(args[0].run(info).gsi(info.clone()).to_string()).to() } - BuiltinFunction::Format => { - if let VDataEnum::String(mut text) = args.first().unwrap().run(vars, info).inner() { + BuiltinFunction::Format => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(text) = v { + let mut text = text.to_owned(); for (i, arg) in args.iter().skip(1).enumerate() { - text = text.replace( - &format!("{{{i}}}"), - &format!( - "{}", - if let VDataEnum::String(v) = &arg.run(vars, info).data().0 { - v - } else { - unreachable!() - } - ), - ); + arg.run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(v) = v { + text = text.replace(&format!("{{{i}}}"), v); + } else { + unreachable!() + } + }) } VDataEnum::String(text).to() } else { unreachable!() } - } - BuiltinFunction::ParseInt => { - if args.len() == 1 { - if let VDataEnum::String(s) = &args[0].run(vars, info).data().0 { - if let Ok(s) = s.parse() { - VDataEnum::Int(s).to() - } else { - VDataEnum::Tuple(vec![]).to() - } + }), + BuiltinFunction::ParseInt => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(s) = v { + if let Ok(s) = s.parse() { + VDataEnum::Int(s).to() } else { - unreachable!("parse arg not string") + VDataEnum::Tuple(vec![]).to() } } else { - unreachable!("parse args != 1") + unreachable!("parse arg not string") } - } - BuiltinFunction::ParseFloat => { - if args.len() == 1 { - if let VDataEnum::String(s) = &args[0].run(vars, info).data().0 { - if let Ok(s) = s.parse() { - VDataEnum::Float(s).to() - } else { - VDataEnum::Tuple(vec![]).to() - } + }), + BuiltinFunction::ParseFloat => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(s) = v { + if let Ok(s) = s.parse() { + VDataEnum::Float(s).to() } else { - unreachable!("parse arg not string") + VDataEnum::Tuple(vec![]).to() } } else { - unreachable!("parse args != 1") + unreachable!("parse arg not string") } - } - BuiltinFunction::Run => { - if args.len() >= 1 { - if let VDataEnum::Function(f) = &args[0].run(vars, info).data().0 { - if f.inputs.len() != args.len() - 1 { - unreachable!() - } - for (i, var) in f.inputs.iter().enumerate() { - let val = args[i + 1].run(vars, info); - vars[*var] = val; - } - f.run(vars, info) - } else { - unreachable!() + }), + BuiltinFunction::Run => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::Function(f) = v { + if f.inputs.len() != args.len() - 1 { + unreachable!("wrong input count") } + for (i, var) in f.inputs.iter().enumerate() { + let val = args[i + 1].run(info).clone_data(); + *var.lock().unwrap() = val; + } + f.run(info) } else { unreachable!() } - } - BuiltinFunction::Thread => { - if args.len() >= 1 { - if let VDataEnum::Function(f) = args[0].run(vars, info).inner() { - if f.inputs.len() != args.len() - 1 { - unreachable!() - } - // to prevent weird stuff from happening, the function args will be stored in different Arc>s. This means that the args are different for each thread, while any variables that are captured from outside will be shared. - let mut thread_vars = vars.clone(); - let mut run_input_types = vec![]; - for (i, var) in f.inputs.iter().enumerate() { - let val = args[i + 1].run(vars, info); - run_input_types.push(val.out_single()); - thread_vars[*var] = val; - } - let out_type = f.out(&run_input_types); - let libs = info.clone(); - VDataEnum::Thread( - VDataThreadEnum::Running(std::thread::spawn(move || { - f.run(&mut thread_vars, &libs) - })) - .to(), - out_type, - ) - .to() - } else { - unreachable!() + }), + BuiltinFunction::Thread => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::Function(f) = v { + if f.inputs.len() != args.len() - 1 { + unreachable!("wrong input count") } + let mut run_input_types = vec![]; + for (i, var) in f.inputs.iter().enumerate() { + let val = args[i + 1].run(info).clone_data(); + run_input_types.push(val.out_single()); + *var.lock().unwrap() = val; + } + let out_type = f.out(&run_input_types); + let info = Arc::clone(info); + let f = Arc::clone(f); + VDataEnum::Thread( + VDataThreadEnum::Running(std::thread::spawn(move || f.run(&info))).to(), + out_type, + ) + .to() } else { unreachable!() } - } - BuiltinFunction::Await => { - if args.len() == 1 { - if let VDataEnum::Thread(t, _) = &args[0].run(vars, info).data().0 { - t.get() - } else { - unreachable!() - } + }), + BuiltinFunction::Await => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::Thread(t, _) = v { + t.get() } else { unreachable!() } - } - BuiltinFunction::Sleep => { - if args.len() == 1 { - match &args[0].run(vars, info).data().0 { - VDataEnum::Int(v) => std::thread::sleep(Duration::from_secs(*v as _)), - VDataEnum::Float(v) => std::thread::sleep(Duration::from_secs_f64(*v)), - _ => unreachable!(), - } - 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 _)), + VDataEnum::Float(v) => std::thread::sleep(Duration::from_secs_f64(*v)), + _ => unreachable!(), } - } + VDataEnum::Tuple(vec![]).to() + }), Self::Exit => { if let Some(s) = args.first() { - if let VDataEnum::Int(v) = &s.run(vars, info).data().0 { - std::process::exit(*v as _); - } else { - std::process::exit(1); - } + let code = s.run(info).operate_on_data_immut(|v| { + if let VDataEnum::Int(v) = v { + *v + } else { + 1 + } + }); + std::process::exit(code as _); } else { std::process::exit(1); } } - Self::FsList => { - if args.len() > 0 { - if let VDataEnum::String(path) = &args[0].run(vars, info).data().0 { - if args.len() > 1 { - eprintln!("NOT YET IMPLEMENTED (TODO!): fs_list advanced filters") - } - match std::fs::read_dir(path) { - Ok(entries) => VDataEnum::List( - VSingleType::String.into(), - entries - .filter_map(|entry| { - if let Ok(entry) = entry { - Some( - VDataEnum::String( - entry.path().to_string_lossy().into_owned(), - ) - .to(), + Self::FsList => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(path) = v { + if args.len() > 1 { + eprintln!("NOT YET IMPLEMENTED (TODO!): fs_list advanced filters") + } + match std::fs::read_dir(path) { + Ok(entries) => VDataEnum::List( + VSingleType::String.into(), + entries + .filter_map(|entry| { + if let Ok(entry) = entry { + Some( + VDataEnum::String( + entry.path().to_string_lossy().into_owned(), ) - } else { - None - } - }) - .collect(), - ) - .to(), - Err(e) => VDataEnum::EnumVariant( - EV_ERR, - Box::new(VDataEnum::String(e.to_string()).to()), - ) - .to(), - } - } else { - unreachable!("fs_list first arg not a string") + .to(), + ) + } else { + None + } + }) + .collect(), + ) + .to(), + Err(e) => VDataEnum::EnumVariant( + EV_ERR, + Box::new(VDataEnum::String(e.to_string()).to()), + ) + .to(), } } else { - unreachable!("fs_list without args") + unreachable!("fs_list first arg not a string") } - } - Self::FsRead => { - if args.len() > 0 { - if let VDataEnum::String(path) = &args[0].run(vars, info).data().0 { - match std::fs::read(path) { - Ok(data) => VDataEnum::List( - VSingleType::Int.into(), - data.into_iter() - .map(|v| VDataEnum::Int(v as _).to()) - .collect(), - ) - .to(), - Err(e) => VDataEnum::EnumVariant( - EV_ERR, - Box::new(VDataEnum::String(e.to_string()).to()), - ) - .to(), - } - } else { - unreachable!("fs_read first arg not a string") + }), + Self::FsRead => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(path) = v { + match std::fs::read(path) { + Ok(data) => VDataEnum::List( + VSingleType::Int.into(), + data.into_iter() + .map(|v| VDataEnum::Int(v as _).to()) + .collect(), + ) + .to(), + Err(e) => VDataEnum::EnumVariant( + EV_ERR, + Box::new(VDataEnum::String(e.to_string()).to()), + ) + .to(), } } else { - unreachable!("fs_read without args") + unreachable!("fs_read first arg not a string") } - } - Self::FsWrite => { - if args.len() > 1 { - if let (VDataEnum::String(path), VDataEnum::List(_, data)) = ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { + }), + Self::FsWrite => args[0].run(info).operate_on_data_immut(|path| { + args[1].run(info).operate_on_data_immut(|bytes| { + if let (VDataEnum::String(path), VDataEnum::List(_, data)) = (path, bytes) { if let Some(bytes) = vdata_to_bytes(&data) { let file_path: PathBuf = path.into(); if let Some(p) = file_path.parent() { @@ -1087,476 +1056,369 @@ impl BuiltinFunction { .to(), } } else { - unreachable!( - "fs_write first arg not a string or second arg not a [int]" - ) + unreachable!("fs_write data arg not a [int]") } } else { - unreachable!("fs_write second arg not a [int]") + unreachable!("fs_write wrong args") + } + }) + }), + Self::BytesToString => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::List(_, byte_data) = v { + if let Some(bytes) = vdata_to_bytes(&byte_data) { + match String::from_utf8(bytes) { + Ok(v) => VDataEnum::String(v).to(), + Err(e) => { + let err = e.to_string(); + VDataEnum::EnumVariant( + EV_ERR, + Box::new( + VDataEnum::Tuple(vec![ + VDataEnum::String( + String::from_utf8_lossy(&e.into_bytes()) + .into_owned(), + ) + .to(), + VDataEnum::String(err).to(), + ]) + .to(), + ), + ) + .to() + } + } + } else { + unreachable!("bytes_to_string arg not [int]") } } else { - unreachable!("fs_write without 2 args") + unreachable!("bytes_to_string first arg not [int]") } - } - Self::BytesToString => { - if args.len() == 1 { - if let VDataEnum::List(_, byte_data) = &args[0].run(vars, info).data().0 { - if let Some(bytes) = vdata_to_bytes(&byte_data) { - match String::from_utf8(bytes) { - Ok(v) => VDataEnum::String(v).to(), - Err(e) => { - let err = e.to_string(); - VDataEnum::EnumVariant( - EV_ERR, - Box::new( - VDataEnum::Tuple(vec![ - VDataEnum::String( - String::from_utf8_lossy(&e.into_bytes()) - .into_owned(), - ) - .to(), - VDataEnum::String(err).to(), - ]) - .to(), - ), - ) - .to() + }), + Self::StringToBytes => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::String(s) = v { + VDataEnum::List( + VSingleType::Int.into(), + s.bytes().map(|v| VDataEnum::Int(v as isize).to()).collect(), + ) + .to() + } else { + unreachable!("string_to_bytes arg not string") + } + }), + Self::RunCommand | Self::RunCommandGetBytes => { + args[0].run(info).operate_on_data_immut(|v| { + args[1].run(info).operate_on_data_immut(|v2| { + if let VDataEnum::String(s) = v { + let mut command = std::process::Command::new(s); + if args.len() > 1 { + if let VDataEnum::List(_, args) = v2 { + for arg in args { + arg.operate_on_data_immut(|v| { + if let VDataEnum::String(v) = v { + command.arg(v); + } else { + unreachable!("run_command second arg not [string].") + } + }) + } + } else { + unreachable!("run_command second arg not [string]") } } + match command.output() { + Ok(out) => VDataEnum::Tuple(vec![ + if let Some(code) = out.status.code() { + VDataEnum::Int(code as _) + } else { + VDataEnum::Tuple(vec![]) + } + .to(), + match self { + Self::RunCommandGetBytes => VDataEnum::List( + VSingleType::Int.into(), + out.stdout + .iter() + .map(|v| VDataEnum::Int(*v as _).to()) + .collect(), + ), + _ => VDataEnum::String( + String::from_utf8_lossy(&out.stdout).into_owned(), + ), + } + .to(), + match self { + Self::RunCommandGetBytes => VDataEnum::List( + VSingleType::Int.into(), + out.stderr + .iter() + .map(|v| VDataEnum::Int(*v as _).to()) + .collect(), + ), + _ => VDataEnum::String( + String::from_utf8_lossy(&out.stderr).into_owned(), + ), + } + .to(), + ]) + .to(), + Err(e) => VDataEnum::EnumVariant( + EV_ERR, + Box::new(VDataEnum::String(e.to_string()).to()), + ) + .to(), + } } else { - unreachable!("bytes_to_string arg not [int]") + unreachable!("run_command not string arg") } - } else { - unreachable!("bytes_to_string first arg not [int]") - } - } else { - unreachable!("bytes_to_string not 1 arg") - } + }) + }) } - Self::StringToBytes => { - if args.len() == 1 { - if let VDataEnum::String(s) = &args[0].run(vars, info).data().0 { - VDataEnum::List( - VSingleType::Int.into(), - s.bytes().map(|v| VDataEnum::Int(v as isize).to()).collect(), - ) - .to() - } else { - unreachable!("string_to_bytes arg not string") - } - } else { - unreachable!("string_to_bytes not 1 arg") - } - } - Self::RunCommand | Self::RunCommandGetBytes => { - if args.len() > 0 { - if let VDataEnum::String(s) = &args[0].run(vars, info).data().0 { - let mut command = std::process::Command::new(s); - if args.len() > 1 { - if let VDataEnum::List(_, args) = &args[1].run(vars, info).data().0 { - for arg in args { - if let VDataEnum::String(v) = &arg.data().0 { - command.arg(v); - } else { - unreachable!("run_command second arg not [string].") - } - } - } else { - unreachable!("run_command second arg not [string]") - } - } - match command.output() { - Ok(out) => VDataEnum::Tuple(vec![ - if let Some(code) = out.status.code() { - VDataEnum::Int(code as _) - } else { - VDataEnum::Tuple(vec![]) - } - .to(), - match self { - Self::RunCommandGetBytes => VDataEnum::List( - VSingleType::Int.into(), - out.stdout - .iter() - .map(|v| VDataEnum::Int(*v as _).to()) - .collect(), - ), - _ => VDataEnum::String( - String::from_utf8_lossy(&out.stdout).into_owned(), - ), - } - .to(), - match self { - Self::RunCommandGetBytes => VDataEnum::List( - VSingleType::Int.into(), - out.stderr - .iter() - .map(|v| VDataEnum::Int(*v as _).to()) - .collect(), - ), - _ => VDataEnum::String( - String::from_utf8_lossy(&out.stderr).into_owned(), - ), - } - .to(), - ]) - .to(), - Err(e) => VDataEnum::EnumVariant( - EV_ERR, - Box::new(VDataEnum::String(e.to_string()).to()), - ) - .to(), - } - } else { - unreachable!("run_command not string arg") - } - } else { - unreachable!("run_command not 1 arg") - } - } - Self::Not => { - if let VDataEnum::Bool(v) = &args[0].run(vars, info).data().0 { + Self::Not => args[0].run(info).operate_on_data_immut(|v| { + if let VDataEnum::Bool(v) = v { VDataEnum::Bool(!v).to() } else { unreachable!() } - } - Self::And => { - if let VDataEnum::Bool(a) = &args[0].run(vars, info).data().0 { + }), + Self::And => args[0].run(info).operate_on_data_immut(|a| { + if let VDataEnum::Bool(a) = a { if *a == false { VDataEnum::Bool(false).to() } else { - if let VDataEnum::Bool(b) = &args[1].run(vars, info).data().0 { - VDataEnum::Bool(*b).to() - } else { - unreachable!() - } + args[1].run(info).operate_on_data_immut(|b| { + if let VDataEnum::Bool(b) = b { + VDataEnum::Bool(*b).to() + } else { + unreachable!() + } + }) } } else { unreachable!() } - } - Self::Or => { - if let VDataEnum::Bool(a) = &args[0].run(vars, info).data().0 { + }), + Self::Or => args[0].run(info).operate_on_data_immut(|a| { + if let VDataEnum::Bool(a) = a { if *a == true { VDataEnum::Bool(true).to() } else { - if let VDataEnum::Bool(b) = &args[1].run(vars, info).data().0 { - VDataEnum::Bool(*b).to() - } else { - unreachable!() - } + args[1].run(info).operate_on_data_immut(|b| { + if let VDataEnum::Bool(b) = b { + VDataEnum::Bool(*b).to() + } else { + unreachable!() + } + }) } } else { unreachable!() } - } - Self::Add => { - if args.len() == 2 { - match ( - args[0].run(vars, info).inner(), - args[1].run(vars, info).inner(), - ) { - (VDataEnum::String(mut a), VDataEnum::String(b)) => { - a.push_str(b.as_str()); - VDataEnum::String(a).to() - } - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a + b).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Float(a as f64 + b).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Float(a + b as f64).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a + b).to(), - _ => unreachable!("add: not a number/string"), + }), + Self::Add => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::String(a), VDataEnum::String(b)) => { + VDataEnum::String(format!("{a}{b}")).to() } - } else { - unreachable!("add: not 2 args") - } - } - Self::Sub => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a - b).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Float(*a as f64 - *b).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Float(*a - *b as f64).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a - b).to(), - _ => unreachable!("sub: not a number"), + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a + b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float(*a as f64 + b).to() } - } else { - unreachable!("sub: not 2 args") - } - } - Self::Mul => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a * b).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Float(*a as f64 * b).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Float(a * *b as f64).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a * b).to(), - _ => unreachable!("mul: not a number"), + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(a + *b as f64).to() } - } else { - unreachable!("mul: not 2 args") - } - } - Self::Div => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a / b).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Float(*a as f64 / b).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Float(a / *b as f64).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a / b).to(), - _ => unreachable!("div: not a number"), + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a + b).to(), + _ => unreachable!("add: not a number/string"), + }) + }), + Self::Sub => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a - b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float(*a as f64 - *b).to() } - } else { - unreachable!("div: not 2 args") - } - } - Self::Mod => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a % b).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Float(*a as f64 % b).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Float(a % *b as f64).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a % b).to(), - _ => unreachable!("mod: not a number"), + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(*a - *b as f64).to() } - } else { - unreachable!("mod: not 2 args") - } - } - Self::Pow => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(if *b == 0 { - 1 - } else if *b > 0 { - (*a).pow(*b as _) - } else { - 0 - }) - .to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Float((*a as f64).powf(*b)).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Float((*a).powi(*b as _)).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => { - VDataEnum::Float((*a).powf(*b)).to() - } - _ => unreachable!("pow: not a number"), + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a - b).to(), + _ => unreachable!("sub: not a number"), + }) + }), + Self::Mul => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a * b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float(*a as f64 * b).to() } - } else { - unreachable!("pow: not 2 args") - } - } - Self::Eq => { - if args.len() == 2 { - VDataEnum::Bool(args[0].run(vars, info) == args[1].run(vars, info)).to() - } else { - unreachable!("eq: not 2 args") - } - } - Self::Gt => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(*a > *b).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Bool(*a as f64 > *b).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Bool(*a > *b as f64).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(*a > *b).to(), - _ => unreachable!("gt: not a number"), + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(a * *b as f64).to() } - } else { - unreachable!("gt: not 2 args") - } - } - Self::Lt => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(*a < *b).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Bool((*a as f64) < *b).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Bool(*a < *b as f64).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(*a < *b).to(), - _ => unreachable!("lt: not a number"), + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a * b).to(), + _ => unreachable!("mul: not a number"), + }) + }), + Self::Div => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a / b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float(*a as f64 / b).to() } - } else { - unreachable!("lt: not 2 args") - } - } - Self::Gtoe => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(*a >= *b).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Bool(*a as f64 >= *b).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Bool(*a >= *b as f64).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => { - VDataEnum::Bool(*a >= *b).to() - } - _ => unreachable!("gtoe: not a number"), + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(a / *b as f64).to() } - } else { - unreachable!("gtoe: not 2 args") - } - } - Self::Ltoe => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(*a <= *b).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Bool(*a as f64 <= *b).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Bool(*a <= *b as f64).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => { - VDataEnum::Bool(*a <= *b).to() - } - _ => unreachable!("ltoe: not a number"), + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a / b).to(), + _ => unreachable!("div: not a number"), + }) + }), + Self::Mod => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a % b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float(*a as f64 % b).to() } - } else { - unreachable!("ltoe: not 2 args") - } - } - Self::Min => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int((*a).min(*b)).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Float((*a as f64).min(*b)).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Float((*a).min(*b as f64)).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => { - VDataEnum::Float((*a).min(*b)).to() - } - _ => unreachable!("min: not a number"), + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(a % *b as f64).to() } - } else { - unreachable!("min: not 2 args") - } - } - Self::Max => { - if args.len() == 2 { - match ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { - (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int((*a).max(*b)).to(), - (VDataEnum::Int(a), VDataEnum::Float(b)) => { - VDataEnum::Float((*a as f64).max(*b)).to() - } - (VDataEnum::Float(a), VDataEnum::Int(b)) => { - VDataEnum::Float((*a).max(*b as f64)).to() - } - (VDataEnum::Float(a), VDataEnum::Float(b)) => { - VDataEnum::Float((*a).max(*b)).to() - } - _ => unreachable!("max: not a number"), + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a % b).to(), + _ => unreachable!("mod: not a number"), + }) + }), + Self::Pow => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(if *b == 0 { + 1 + } else if *b > 0 { + (*a).pow(*b as _) + } else { + 0 + }) + .to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float((*a as f64).powf(*b)).to() } - } else { - unreachable!("max: not 2 args") - } - } - Self::Push => { - if args.len() == 2 { - // Since this is a reference, it is safe to assume that make_mut() would do nothing. - if let VDataEnum::Reference(v) = &args[0].run(vars, info).data().0 { - if let VDataEnum::List(_, v) = &mut v.data().0 { - v.push(args[1].run(vars, info)); + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float((*a).powi(*b as _)).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => { + VDataEnum::Float((*a).powf(*b)).to() + } + _ => unreachable!("pow: not a number"), + }) + }), + Self::Eq => VDataEnum::Bool(args[0].run(info) == args[1].run(info)).to(), + Self::Ne => VDataEnum::Bool(args[0].run(info) != args[1].run(info)).to(), + Self::Gt => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(*a > *b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Bool(*a as f64 > *b).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Bool(*a > *b as f64).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(*a > *b).to(), + _ => unreachable!("gt: not a number"), + }) + }), + Self::Lt => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(*a < *b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Bool((*a as f64) < *b).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Bool(*a < *b as f64).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(*a < *b).to(), + _ => unreachable!("lt: not a number"), + }) + }), + Self::Gtoe => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(*a >= *b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Bool(*a as f64 >= *b).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Bool(*a >= *b as f64).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(*a >= *b).to(), + _ => unreachable!("gtoe: not a number"), + }) + }), + Self::Ltoe => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(*a <= *b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Bool(*a as f64 <= *b).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Bool(*a <= *b as f64).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(*a <= *b).to(), + _ => unreachable!("ltoe: not a number"), + }) + }), + Self::Min => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int((*a).min(*b)).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float((*a as f64).min(*b)).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float((*a).min(*b as f64)).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => { + VDataEnum::Float((*a).min(*b)).to() + } + _ => unreachable!("min: not a number"), + }) + }), + Self::Max => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| match (a, b) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int((*a).max(*b)).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float((*a as f64).max(*b)).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float((*a).max(*b as f64)).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => { + VDataEnum::Float((*a).max(*b)).to() + } + _ => unreachable!("max: not a number"), + }) + }), + Self::Push => args[0].run(info).operate_on_data_mut(|list| { + if let VDataEnum::Reference(v) = list { + v.operate_on_data_mut(|list| { + if let VDataEnum::List(_, v) = list { + v.push(args[1].run(info)); } VDataEnum::Tuple(vec![]).to() - } else { - unreachable!("push: not a reference") - } + }) } else { - unreachable!("push: not 2 args") + unreachable!("push: not a reference") } - } - Self::Insert => { - if args.len() == 3 { - // this being a reference means we wont need to call make_mut() later, so a .as_ref() borrow is enough. - if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = ( - &args[0].run(vars, info).data().0, - &args[2].run(vars, info).data().0, - ) { - if let VDataEnum::List(_, v) = &mut v.data().0 { - v.insert(*i as _, args[1].run(vars, info)); - } + }), + Self::Insert => args[0].run(info).operate_on_data_mut(|v| { + args[1].run(info).operate_on_data_immut(|i| { + // TODO: find out why the fuck this helps + if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = (v, i) { + v.operate_on_data_mut(|v| { + if let VDataEnum::List(_, v) = v { + v.insert(*i as _, args[2].run(info)); + } + }); VDataEnum::Tuple(vec![]).to() } else { unreachable!("insert: not a reference and index") } - } else { - unreachable!("insert: not 3 args") - } - } - Self::Pop => { - if args.len() == 1 { - // this being a reference means we wont need to call make_mut() later, so a .as_ref() borrow is enough. - if let VDataEnum::Reference(v) = &args[0].run(vars, info).data().0 { - if let VDataEnum::List(_, v) = &mut v.data.lock().unwrap().0 { + }) + }), + Self::Pop => args[0].run(info).operate_on_data_mut(|v| { + if let VDataEnum::Reference(v) = v { + v.operate_on_data_mut(|v| { + if let VDataEnum::List(_, v) = v { if let Some(v) = v.pop() { VDataEnum::Tuple(vec![v]) } else { @@ -1566,53 +1428,44 @@ impl BuiltinFunction { } else { unreachable!("pop: not a list") } - } else { - unreachable!("pop: not a reference") - } + }) } else { - unreachable!("pop: not 1 arg") + unreachable!("pop: not a reference") } - } - Self::Remove => { - if args.len() == 2 { + }), + Self::Remove => args[0].run(info).operate_on_data_mut(|v| { + args[1].run(info).operate_on_data_immut(|i| // this being a reference means we wont need to call make_mut() later, so a .as_ref() borrow is enough. - if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, + if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = (v, i ) { - if let VDataEnum::List(_, v) = &mut v.data.lock().unwrap().0 { - if *i >= 0 && v.len() > *i as _ { - let v = v.remove(*i as _); - VDataEnum::Tuple(vec![v]).to() + v.operate_on_data_mut(|v| { + if let VDataEnum::List(_, v) = v { + if *i >= 0 && v.len() > *i as _ { + let v = v.remove(*i as _); + VDataEnum::Tuple(vec![v]).to() + } else { + VDataEnum::Tuple(vec![]).to() + } } else { - VDataEnum::Tuple(vec![]).to() - } - } else { - unreachable!("remove: not a list") - } + unreachable!("remove: not a list") + }}) } else { unreachable!("remove: not a reference and index") - } - } else { - unreachable!("remove: not 2 args") - } - } - Self::Get => { - if args.len() == 2 { - if let (container, VDataEnum::Int(i)) = ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { + }) + }), + Self::Get => args[0].run(info).operate_on_data_immut(|container| { + args[1].run(info).operate_on_data_immut(|i| { + if let VDataEnum::Int(i) = i { if *i >= 0 { match match container { - VDataEnum::Reference(v) => match &v.data().0 { + VDataEnum::Reference(v) => v.operate_on_data_immut(|v| match v { VDataEnum::List(_, v) | VDataEnum::Tuple(v) => { v.get(*i as usize).map(|v| v.clone()) } _ => unreachable!( "get: reference to something other than list/tuple" ), - }, + }), VDataEnum::List(_, v) | VDataEnum::Tuple(v) => { v.get(*i as usize).map(|v| v.clone()) } @@ -1627,19 +1480,14 @@ impl BuiltinFunction { } else { unreachable!("get: not a list/tuple/reference and index") } - } else { - unreachable!("get: not 2 args") - } - } - Self::GetRef => { - if args.len() == 2 { - if let (VDataEnum::Reference(container), VDataEnum::Int(i)) = ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { + }) + }), + Self::GetRef => args[0].run(info).operate_on_data_mut(|container| { + args[1].run(info).operate_on_data_immut(|i| { + if let (VDataEnum::Reference(container), VDataEnum::Int(i)) = (container, i) { if *i >= 0 { // we can get mutably because this is the content of a reference - match match &mut container.data().0 { + match container.operate_on_data_mut(|container| match container { VDataEnum::List(_, v) | VDataEnum::Tuple(v) => { if let Some(v) = v.get_mut(*i as usize) { Some(VDataEnum::Reference(v.clone_mut()).to()) @@ -1648,7 +1496,7 @@ impl BuiltinFunction { } } _ => unreachable!("get: not a reference/list/tuple"), - } { + }) { Some(v) => VDataEnum::Tuple(vec![v]).to(), None => VDataEnum::Tuple(vec![]).to(), } @@ -1658,27 +1506,25 @@ impl BuiltinFunction { } else { unreachable!("get_ref: not a reference and index") } - } else { - unreachable!("get: not 2 args") - } - } + }) + }), Self::Len => { if args.len() == 1 { - VDataEnum::Int(match &args[0].run(vars, info).data().0 { + VDataEnum::Int(args[0].run(info).operate_on_data_immut(|v| match v { VDataEnum::String(v) => v.len(), VDataEnum::Tuple(v) => v.len(), VDataEnum::List(_, v) => v.len(), _ => unreachable!("len: invalid type"), - } as _) + }) as _) .to() } else { unreachable!("len: not 1 arg") } } - Self::Contains => { - if args.len() == 2 { - if let VDataEnum::String(a1) = &args[0].run(vars, info).data().0 { - if let VDataEnum::String(a2) = &args[1].run(vars, info).data().0 { + Self::Contains => args[0].run(info).operate_on_data_immut(|a1| { + args[1].run(info).operate_on_data_immut(|a2| { + if let VDataEnum::String(a1) = a2 { + if let VDataEnum::String(a2) = a2 { VDataEnum::Bool(a1.contains(a2.as_str())).to() } else { unreachable!() @@ -1686,14 +1532,12 @@ impl BuiltinFunction { } else { unreachable!() } - } else { - unreachable!() - } - } - Self::StartsWith => { - if args.len() == 2 { - if let VDataEnum::String(a1) = &args[0].run(vars, info).data().0 { - if let VDataEnum::String(a2) = &args[1].run(vars, info).data().0 { + }) + }), + Self::StartsWith => args[0].run(info).operate_on_data_immut(|a1| { + args[1].run(info).operate_on_data_immut(|a2| { + if let VDataEnum::String(a1) = a2 { + if let VDataEnum::String(a2) = a2 { VDataEnum::Bool(a1.starts_with(a2.as_str())).to() } else { unreachable!() @@ -1701,14 +1545,12 @@ impl BuiltinFunction { } else { unreachable!() } - } else { - unreachable!() - } - } - Self::EndsWith => { - if args.len() == 2 { - if let VDataEnum::String(a1) = &args[0].run(vars, info).data().0 { - if let VDataEnum::String(a2) = &args[1].run(vars, info).data().0 { + }) + }), + Self::EndsWith => args[0].run(info).operate_on_data_immut(|a1| { + args[1].run(info).operate_on_data_immut(|a2| { + if let VDataEnum::String(a1) = a2 { + if let VDataEnum::String(a2) = a2 { VDataEnum::Bool(a1.ends_with(a2.as_str())).to() } else { unreachable!() @@ -1716,14 +1558,10 @@ impl BuiltinFunction { } else { unreachable!() } - } else { - unreachable!() - } - } - Self::IndexOf => { - if args.len() == 2 { - let find_in = args[0].run(vars, info); - let pat = args[1].run(vars, info); + }) + }), + Self::IndexOf => args[0].run(info).operate_on_data_immut(|find_in| { + args[1].run(info).operate_on_data_immut(|pat| { fn find(find_in: &String, pat: &String) -> VData { if let Some(found_byte_index) = find_in.find(pat) { if let Some(char_index) = find_in.char_indices().enumerate().find_map( @@ -1743,110 +1581,87 @@ impl BuiltinFunction { VDataEnum::Tuple(vec![]).to() } } - let o = match (&find_in.data().0, &pat.data().0) { + let o = match (find_in, pat) { (VDataEnum::String(a), VDataEnum::String(b)) => find(a, b), - (VDataEnum::String(a), VDataEnum::Reference(b)) => match &b.data().0 { - VDataEnum::String(b) => find(a, b), - _ => unreachable!(), - }, - (VDataEnum::Reference(a), VDataEnum::String(b)) => match &a.data().0 { - VDataEnum::String(a) => find(a, b), - _ => unreachable!(), - }, - (VDataEnum::Reference(a), VDataEnum::Reference(b)) => { - if a.ptr_eq(b) { - // point to the same string - // (this is required because a.lock() would cause b.lock() to wait indefinitely if you pass a two references to the same string here) - VDataEnum::Int(0).to() - } else { - match (&a.data().0, &b.data().0) { - (VDataEnum::String(a), VDataEnum::String(b)) => find(a, b), - _ => unreachable!(), - } - } - } _ => unreachable!(), }; o + }) + }), + Self::Trim => args[0].run(info).operate_on_data_immut(|a| { + if let VDataEnum::String(a) = a { + VDataEnum::String(a.trim().to_string()).to() } else { unreachable!() } - } - Self::Trim => { - if args.len() == 1 { - if let VDataEnum::String(a) = &args[0].run(vars, info).data().0 { - VDataEnum::String(a.trim().to_string()).to() - } else { + }), + Self::Substring => args[0].run(info).operate_on_data_immut(|a| { + if let VDataEnum::String(a) = a { + if args.len() > 3 { unreachable!() } - } else { - unreachable!() - } - } - Self::Substring => { - if args.len() >= 2 { - if let VDataEnum::String(a) = &args[0].run(vars, info).data().0 { - if args.len() > 3 { - unreachable!() - } - let left = if let VDataEnum::Int(left) = &args[1].run(vars, info).data().0 { + let left = args[1].run(info).operate_on_data_immut(|left| { + if let VDataEnum::Int(left) = left { *left } else { unreachable!() - }; - let len = if args.len() == 3 { - if let VDataEnum::Int(len) = &args[2].run(vars, info).data().0 { + } + }); + let len = if args.len() == 3 { + args[2].run(info).operate_on_data_immut(|len| { + if let VDataEnum::Int(len) = len { Some(*len) } else { unreachable!() } + }) + } else { + None + }; + let left = if left >= 0 { + left as usize + } else { + (a.len() - 1).saturating_sub(left.abs() as _) + }; + if let Some(len) = len { + if len >= 0 { + VDataEnum::String( + a.chars() + .skip(left) + .take((len as usize).saturating_sub(left)) + .collect(), + ) + .to() } else { - None - }; - let left = if left >= 0 { left as usize } else { 0 }; - if let Some(len) = len { - if len >= 0 { - VDataEnum::String( - a.chars() - .skip(left) - .take((len as usize).saturating_sub(left)) - .collect(), - ) - .to() - } else { - // negative end index => max length - VDataEnum::String( - a.chars().skip(left).take(len.abs() as usize).collect(), - ) - .to() - } - } else { - VDataEnum::String(a.chars().skip(left).collect()).to() + // negative end index => max length + VDataEnum::String( + a.chars().skip(left).take(len.abs() as usize).collect(), + ) + .to() } } else { - unreachable!() + VDataEnum::String(a.chars().skip(left).collect()).to() } } else { unreachable!() } - } - Self::Replace => { - if let (VDataEnum::String(a), VDataEnum::String(b), VDataEnum::String(c)) = ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - &args[2].run(vars, info).data().0, - ) { - VDataEnum::String(a.replace(b, c)).to() - } else { - unreachable!() - } - } - Self::Regex => { - if args.len() == 2 { - if let (VDataEnum::String(a), VDataEnum::String(regex)) = ( - &args[0].run(vars, info).data().0, - &args[1].run(vars, info).data().0, - ) { + }), + Self::Replace => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|b| { + args[2].run(info).operate_on_data_immut(|c| { + if let (VDataEnum::String(a), VDataEnum::String(b), VDataEnum::String(c)) = + (a, b, c) + { + VDataEnum::String(a.replace(b, c)).to() + } else { + unreachable!() + } + }) + }) + }), + Self::Regex => args[0].run(info).operate_on_data_immut(|a| { + args[1].run(info).operate_on_data_immut(|regex| { + if let (VDataEnum::String(a), VDataEnum::String(regex)) = (a, regex) { match regex::Regex::new(regex.as_str()) { Ok(regex) => VDataEnum::List( VSingleType::String.to(), @@ -1865,10 +1680,8 @@ impl BuiltinFunction { } else { unreachable!() } - } else { - unreachable!() - } - } + }) + }), } } } @@ -1876,17 +1689,20 @@ impl BuiltinFunction { fn vdata_to_bytes(vd: &Vec) -> Option> { let mut bytes = Vec::with_capacity(vd.len()); for b in vd { - if let VDataEnum::Int(b) = &b.data().0 { - bytes.push(if 0 <= *b && *b <= u8::MAX as isize { - *b as u8 - } else if b.is_negative() { - 0 + let b = b.operate_on_data_immut(|b| { + if let VDataEnum::Int(b) = b { + Some(*b) } else { - u8::MAX - }); + None + } + })?; + bytes.push(if 0 <= b && b <= u8::MAX as isize { + b as u8 + } else if b.is_negative() { + 0 } else { - return None; - } + u8::MAX + }); } Some(bytes) } diff --git a/mers/src/script/code_macro.rs b/mers/src/lang/code_macro.rs similarity index 100% rename from mers/src/script/code_macro.rs rename to mers/src/lang/code_macro.rs diff --git a/mers/src/script/code_parsed.rs b/mers/src/lang/code_parsed.rs similarity index 100% rename from mers/src/script/code_parsed.rs rename to mers/src/lang/code_parsed.rs diff --git a/mers/src/script/code_runnable.rs b/mers/src/lang/code_runnable.rs similarity index 68% rename from mers/src/script/code_runnable.rs rename to mers/src/lang/code_runnable.rs index 9a4495c..c61c32d 100755 --- a/mers/src/script/code_runnable.rs +++ b/mers/src/lang/code_runnable.rs @@ -8,15 +8,34 @@ use super::{ val_type::{VSingleType, VType}, }; +#[derive(Clone, Debug)] +pub enum RStatementEnum { + Value(VData), + Tuple(Vec), + List(Vec), + Variable(Arc>, VType, bool), + FunctionCall(Arc, Vec), + BuiltinFunction(BuiltinFunction, Vec), + LibFunction(usize, usize, Vec, VType), + Block(RBlock), + If(RStatement, RStatement, Option), + Loop(RStatement), + For(Arc>, RStatement, RStatement), + Switch(RStatement, Vec<(VType, RStatement)>), + Match(Arc>, Vec<(RStatement, RStatement)>), + IndexFixed(RStatement, usize), + EnumVariant(usize, RStatement), +} + #[derive(Clone, Debug)] pub struct RBlock { pub statements: Vec, } impl RBlock { - pub fn run(&self, vars: &mut Vec, info: &GSInfo) -> VData { + pub fn run(&self, info: &GSInfo) -> VData { let mut last = None; for statement in &self.statements { - last = Some(statement.run(vars, info)); + last = Some(statement.run(info)); } if let Some(v) = last { v @@ -37,14 +56,14 @@ impl RBlock { #[derive(Clone, Debug)] pub struct RFunction { - pub inputs: Vec, + pub inputs: Vec>>, pub input_types: Vec, pub input_output_map: Vec<(Vec, VType)>, pub block: RBlock, } impl RFunction { - pub fn run(&self, vars: &mut Vec, info: &GSInfo) -> VData { - self.block.run(vars, info) + pub fn run(&self, info: &GSInfo) -> VData { + self.block.run(info) } pub fn out(&self, input_types: &Vec) -> VType { self.input_output_map @@ -87,18 +106,25 @@ pub struct RStatement { pub force_output_type: Option, } impl RStatement { - pub fn run(&self, vars: &mut Vec, info: &GSInfo) -> VData { - let out = self.statement.run(vars, info); + pub fn run(&self, info: &GSInfo) -> VData { + let out = self.statement.run(info); if let Some((v, derefs, is_init)) = &self.output_to { - let mut val = v.run(vars, info); - // even if 0 derefs, deref once because it *has* to end on a reference (otherwise writing to it would be unacceptable as the value might not expect to be modified) - for _ in 0..(derefs + 1) { - val = match val.inner().deref() { - Some(v) => v, - None => unreachable!("can't dereference..."), - }; + 'init: { + if *is_init && *derefs == 0 { + if let RStatementEnum::Variable(var, _, _) = v.statement.as_ref() { + *var.lock().unwrap() = out; + break 'init; + } + } + let mut val = v.run(info); + for _ in 0..(*derefs + 1) { + val = match val.deref() { + Some(v) => v, + None => unreachable!("can't dereference..."), + }; + } + val.assign(out); } - val.assign(out.inner()); VDataEnum::Tuple(vec![]).to() } else { out @@ -118,32 +144,14 @@ impl RStatement { } } -#[derive(Clone, Debug)] -pub enum RStatementEnum { - Value(VData), - Tuple(Vec), - List(Vec), - Variable(usize, VType, bool), - FunctionCall(Arc, Vec), - BuiltinFunction(BuiltinFunction, Vec), - LibFunction(usize, usize, Vec, VType), - Block(RBlock), - If(RStatement, RStatement, Option), - Loop(RStatement), - For(usize, RStatement, RStatement), - Switch(RStatement, Vec<(VType, RStatement)>), - Match(usize, Vec<(RStatement, RStatement)>), - IndexFixed(RStatement, usize), - EnumVariant(usize, RStatement), -} impl RStatementEnum { - pub fn run(&self, vars: &mut Vec, info: &GSInfo) -> VData { + pub fn run(&self, info: &GSInfo) -> VData { match self { Self::Value(v) => v.clone(), Self::Tuple(v) => { let mut w = vec![]; for v in v { - w.push(v.run(vars, info)); + w.push(v.run(info)); } VDataEnum::Tuple(w).to() } @@ -151,7 +159,7 @@ impl RStatementEnum { let mut w = vec![]; let mut out = VType { types: vec![] }; for v in v { - let val = v.run(vars, info); + let val = v.run(info); out = out | val.out(); w.push(val); } @@ -159,30 +167,29 @@ impl RStatementEnum { } Self::Variable(v, _, is_ref) => { if *is_ref { - // shared mutability (clone_mut) - VDataEnum::Reference(vars[*v].clone_mut()).to() + VDataEnum::Reference(v.lock().unwrap().clone_mut()).to() } else { - // Copy on Write (clone) - vars[*v].clone() + v.lock().unwrap().clone_data() } } Self::FunctionCall(func, args) => { for (i, input) in func.inputs.iter().enumerate() { - vars[*input] = args[i].run(vars, info); + input.lock().unwrap().assign(args[i].run(info)); } - func.run(vars, info) + func.run(info) } - Self::BuiltinFunction(v, args) => v.run(args, vars, info), - Self::LibFunction(libid, fnid, args, _) => info.libs[*libid] - .run_fn(*fnid, args.iter().map(|arg| arg.run(vars, info)).collect()), - Self::Block(b) => b.run(vars, info), - Self::If(c, t, e) => { - if let VDataEnum::Bool(v) = &c.run(vars, info).data().0 { + Self::BuiltinFunction(v, args) => v.run(args, info), + Self::LibFunction(libid, fnid, args, _) => { + info.libs[*libid].run_fn(*fnid, args.iter().map(|arg| arg.run(info)).collect()) + } + Self::Block(b) => b.run(info), + Self::If(c, t, e) => c.run(info).operate_on_data_immut(|v| { + if let VDataEnum::Bool(v) = v { if *v { - t.run(vars, info) + t.run(info) } else { if let Some(e) = e { - e.run(vars, info) + e.run(info) } else { VDataEnum::Tuple(vec![]).to() } @@ -190,75 +197,71 @@ impl RStatementEnum { } else { unreachable!() } - } + }), Self::Loop(c) => loop { // loops will break if the value matches. - if let Some(break_val) = c.run(vars, info).inner().matches() { + if let Some(break_val) = c.run(info).matches() { break break_val; } }, Self::For(v, c, b) => { // matching values also break with value from a for loop. - let c = c.run(vars, info); - let mut vars = vars.clone(); - let in_loop = |vars: &mut Vec, c| { - vars[*v] = c; - b.run(vars, info) - }; + c.run(info).operate_on_data_immut(|c: &VDataEnum| { + let mut in_loop = |c: VData| { + *v.lock().unwrap() = c; + b.run(info) + }; - let mut oval = VDataEnum::Tuple(vec![]).to(); - match &c.data().0 { - VDataEnum::Int(v) => { - for i in 0..*v { - if let Some(v) = - in_loop(&mut vars, VDataEnum::Int(i).to()).inner().matches() - { - oval = v; - break; + let mut oval = VDataEnum::Tuple(vec![]).to(); + match c { + VDataEnum::Int(v) => { + for i in 0..*v { + if let Some(v) = in_loop(VDataEnum::Int(i).to()).matches() { + oval = v; + break; + } } } + VDataEnum::String(v) => { + for ch in v.chars() { + if let Some(v) = + in_loop(VDataEnum::String(ch.to_string()).to()).matches() + { + oval = v; + break; + } + } + } + VDataEnum::Tuple(v) | VDataEnum::List(_, v) => { + for v in v { + if let Some(v) = in_loop(v.clone()).matches() { + oval = v; + break; + } + } + } + VDataEnum::Function(f) => loop { + if let Some(v) = f.run(info).matches() { + if let Some(v) = in_loop(v).matches() { + oval = v; + break; + } + } else { + break; + } + }, + _ => unreachable!(), } - VDataEnum::String(v) => { - for ch in v.chars() { - if let Some(v) = - in_loop(&mut vars, VDataEnum::String(ch.to_string()).to()) - .inner() - .matches() - { - oval = v; - break; - } - } - } - VDataEnum::Tuple(v) | VDataEnum::List(_, v) => { - for v in v { - if let Some(v) = in_loop(&mut vars, v.clone()).inner().matches() { - oval = v; - break; - } - } - } - VDataEnum::Function(f) => loop { - if let Some(v) = f.run(&mut vars, info).inner().matches() { - if let Some(v) = in_loop(&mut vars, v).inner().matches() { - oval = v; - break; - } - } else { - break; - } - }, - _ => unreachable!(), - } - oval + oval + }) } Self::Switch(switch_on, cases) => { - let switch_on = switch_on.run(vars, info); + let switch_on = switch_on.run(info); let switch_on_type = switch_on.out(); let mut out = VDataEnum::Tuple(vec![]).to(); for (case_type, case_action) in cases.iter() { if switch_on_type.fits_in(case_type, info).is_empty() { - out = case_action.run(vars, info); + out = case_action.run(info); break; } } @@ -267,17 +270,17 @@ impl RStatementEnum { Self::Match(match_on, cases) => 'm: { for (case_condition, case_action) in cases { // [t] => Some(t), t => Some(t), [] | false => None - if let Some(v) = case_condition.run(vars, info).inner().matches() { - let og = { std::mem::replace(&mut vars[*match_on], v) }; - let res = case_action.run(vars, info); - vars[*match_on] = og; + if let Some(v) = case_condition.run(info).matches() { + let og = { std::mem::replace(&mut *match_on.lock().unwrap(), v) }; + let res = case_action.run(info); + *match_on.lock().unwrap() = og; break 'm res; } } VDataEnum::Tuple(vec![]).to() } - Self::IndexFixed(st, i) => st.run(vars, info).get(*i, false).unwrap(), - Self::EnumVariant(e, v) => VDataEnum::EnumVariant(*e, Box::new(v.run(vars, info))).to(), + Self::IndexFixed(st, i) => st.run(info).get(*i).unwrap(), + Self::EnumVariant(e, v) => VDataEnum::EnumVariant(*e, Box::new(v.run(info))).to(), } } pub fn out(&self, info: &GlobalScriptInfo) -> VType { @@ -376,7 +379,7 @@ impl RScript { Ok(Self { main, info }) } pub fn run(&self, args: Vec) -> VData { - let mut vars = Vec::with_capacity(self.info.vars); + let mut vars = vec![]; vars.push( VDataEnum::List( VSingleType::String.into(), @@ -386,10 +389,7 @@ impl RScript { ) .to(), ); - for _i in 1..self.info.vars { - vars.push(VDataEnum::Tuple(vec![]).to()); - } - self.main.run(&mut vars, &self.info) + self.main.run(&self.info) } pub fn info(&self) -> &GSInfo { &self.info diff --git a/mers/src/script/global_info.rs b/mers/src/lang/global_info.rs similarity index 95% rename from mers/src/script/global_info.rs rename to mers/src/lang/global_info.rs index 7230982..71a7961 100755 --- a/mers/src/script/global_info.rs +++ b/mers/src/lang/global_info.rs @@ -8,8 +8,6 @@ pub type GSInfo = Arc; #[derive(Debug)] pub struct GlobalScriptInfo { - pub vars: usize, - pub libs: Vec, pub lib_fns: HashMap, @@ -28,7 +26,6 @@ impl GlobalScriptInfo { impl Default for GlobalScriptInfo { fn default() -> Self { Self { - vars: 0, libs: vec![], lib_fns: HashMap::new(), enum_variants: Self::default_enum_variants(), diff --git a/mers/src/script/mod.rs b/mers/src/lang/mod.rs old mode 100755 new mode 100644 similarity index 100% rename from mers/src/script/mod.rs rename to mers/src/lang/mod.rs diff --git a/mers/src/script/to_runnable.rs b/mers/src/lang/to_runnable.rs similarity index 96% rename from mers/src/script/to_runnable.rs rename to mers/src/lang/to_runnable.rs index 1e4be51..22bbc6d 100755 --- a/mers/src/script/to_runnable.rs +++ b/mers/src/lang/to_runnable.rs @@ -1,17 +1,17 @@ use std::{ collections::HashMap, fmt::{Debug, Display}, - sync::Arc, + sync::{Arc, Mutex}, }; use crate::{ - libs, - script::{ + lang::{ builtins, global_info::GlobalScriptInfo, - val_data::VDataEnum, + val_data::{VData, VDataEnum}, val_type::{VSingleType, VType}, }, + libs, }; use super::{ @@ -158,7 +158,7 @@ impl ToRunnableError { // Local, used to keep local variables separated #[derive(Clone)] struct LInfo { - vars: HashMap, + vars: HashMap>, VType)>, fns: HashMap>, } @@ -200,7 +200,7 @@ fn get_all_functions( s: &SFunction, ginfo: &mut GlobalScriptInfo, linfo: &mut LInfo, - input_vars: &Vec, + input_vars: &Vec>>, inputs: &mut Vec, out: &mut Vec<(Vec, VType)>, ) -> Result<(), ToRunnableError> { @@ -240,12 +240,12 @@ fn function( for (iname, itype) in &s.inputs { let mut itype = itype.to_owned(); stypes(&mut itype, ginfo)?; + let var = Arc::new(Mutex::new(VData::new_placeholder())); linfo .vars - .insert(iname.clone(), (ginfo.vars, itype.clone())); - input_vars.push(ginfo.vars); + .insert(iname.clone(), (Arc::clone(&var), itype.clone())); + input_vars.push(var); input_types.push(itype); - ginfo.vars += 1; } let mut all_outs = vec![]; get_all_functions( @@ -367,13 +367,19 @@ fn statement_adv( if !linfo.vars.contains_key(v) { if let Some((t, is_init)) = to_be_assigned_to { *is_init = true; - linfo.vars.insert(v.to_owned(), (ginfo.vars, t)); - ginfo.vars += 1; + linfo.vars.insert(v.to_owned(), (Arc::new(Mutex::new(VData::new_placeholder())), t)); } } if let Some(var) = linfo.vars.get(v) { - RStatementEnum::Variable(var.0, { - let mut v = var.1.clone(); stypes(&mut v, ginfo)?; v }, *is_ref) + RStatementEnum::Variable( + Arc::clone(&var.0), + { + let mut v = var.1.clone(); + stypes(&mut v, ginfo)?; + v + }, + *is_ref + ) } else { return Err(ToRunnableError::UseOfUndefinedVariable(v.clone())); } @@ -442,7 +448,7 @@ fn statement_adv( } else { // anonymous function => return as value RStatementEnum::Value( - VDataEnum::Function(function(f, ginfo, linfo.clone())?).to(), + VDataEnum::Function(Arc::new(function(f, ginfo, linfo.clone())?)).to(), ) } } @@ -479,11 +485,10 @@ fn statement_adv( if inner.types.is_empty() { return Err(ToRunnableError::ForLoopContainerHasNoInnerTypes); } + let for_loop_var = Arc::new(Mutex::new(VData::new_placeholder())); linfo .vars - .insert(v.clone(), (ginfo.vars, inner)); - let for_loop_var = ginfo.vars; - ginfo.vars += 1; + .insert(v.clone(), (Arc::clone(&for_loop_var), inner)); let block = statement(&b, ginfo, &mut linfo)?; let o = RStatementEnum::For(for_loop_var, container, block); o diff --git a/mers/src/script/val_data.rs b/mers/src/lang/val_data.rs similarity index 53% rename from mers/src/script/val_data.rs rename to mers/src/lang/val_data.rs index 6b3784e..a9913f3 100755 --- a/mers/src/script/val_data.rs +++ b/mers/src/lang/val_data.rs @@ -1,6 +1,6 @@ use std::{ fmt::{self, Debug, Display, Formatter}, - sync::{Arc, Mutex}, + sync::{Arc, Mutex, MutexGuard}, }; use super::{ @@ -9,122 +9,6 @@ use super::{ val_type::{VSingleType, VType}, }; -pub struct VData { - /// (_, mutable) - if false, behave as CopyOnWrite. - pub data: Arc>, -} -impl VData { - /// if self is mutable, assigns the new value to the mutex. - /// if self is immutable, creates a new mutex and sets self to mutable. - pub fn assign(&mut self, new_val: VDataEnum) { - { - let mut d = self.data.lock().unwrap(); - if d.1 { - d.0 = new_val; - return; - } - } - // #[cfg(debug_assertions)] - // eprintln!("VData: assign: overwriting my previous Arc because it was immutable."); - *self = new_val.to(); - } - pub fn inner_replace(&mut self, new_val: VDataEnum) -> VDataEnum { - { - let mut d = self.data.lock().unwrap(); - if d.1 { - return std::mem::replace(&mut d.0, new_val); - } - } - let o = self.data().0.clone(); - *self = new_val.to(); - o - } - /// returns the contained VDataEnum. May or may not clone. - pub fn inner(self) -> VDataEnum { - // Arc::unwrap_or_clone(self.data).lock().unwrap().0 - let o = match Arc::try_unwrap(self.data) { - Ok(v) => std::mem::replace(&mut v.lock().unwrap().0, VDataEnum::Bool(false)), - Err(e) => e.lock().unwrap().0.clone(), - }; - o - } - /// ensures self is mutable, then returns a new instance of VData that is also mutable and uses the same Arc>. - pub fn clone_mut(&mut self) -> Self { - // if not mutable, copy and set to mutable. - self.make_mut(); - // now, both self and the returned value are set to mutable and share the same mutex. - let o = self.clone_mut_assume(); - o - } - /// like clone_mut, but assumes self is already mutable, and therefor does not need to mutate self - /// as the Arc> will stay the same. - pub fn clone_mut_assume(&self) -> Self { - Self { - data: Arc::clone(&self.data), - } - } - pub fn ptr_eq(&self, rhs: &Self) -> bool { - Arc::ptr_eq(&self.data, &rhs.data) - } - /// makes self mutable. might clone. - pub fn make_mut(&mut self) -> &mut Self { - { - let mut s = self.data(); - if !s.1 { - if Arc::strong_count(&self.data) > 1 { - // not mutable yet - clone the value to avoid modifying an immutable one. - #[cfg(debug_assertions)] - eprintln!("VData: actually copying value due to mutation of an immutable shared value. (strong count: {})", Arc::strong_count(&self.data)); - *s = (s.0.clone(), true); - } else { - // value was immutable, but not shared, so we can just make it mutable. - s.1 = true; - } - } - } - self - } - pub fn data(&self) -> std::sync::MutexGuard<(VDataEnum, bool)> { - self.data.lock().unwrap() - } -} -impl Clone for VData { - fn clone(&self) -> Self { - let mut d = self.data.lock().unwrap(); - let o = if d.1 { - // mutable, copy the value to avoid accidentally modifying it. - // DON'T just set it to immutable even if we are the only reference (inner mutability!) - #[cfg(debug_assertions)] - eprintln!( - "VData: Clone: copying value due to clone of a mutable value. (strong count: {})", - Arc::strong_count(&self.data) - ); - d.0.clone().to() - } else { - // immutable, return the same arc (-> avoid cloning) - Self { - data: Arc::clone(&self.data), - } - }; - o - } -} -impl Debug for VData { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let d = self.data.lock().unwrap(); - if d.1 { - write!(f, "(!mutable!):{:?}", d.0) - } else { - write!(f, "(immutable):{:?}", d.0) - } - } -} -impl PartialEq for VData { - fn eq(&self, other: &Self) -> bool { - self.data().0 == other.data().0 - } -} - #[derive(Debug)] pub enum VDataEnum { Bool(bool), @@ -133,17 +17,214 @@ pub enum VDataEnum { String(String), Tuple(Vec), List(VType, Vec), - Function(RFunction), + Function(Arc), Thread(thread::VDataThread, VType), Reference(VData), EnumVariant(usize, Box), } + +pub struct VData(Arc>); +enum VDataInner { + Data(usize, Box), + Mut(Arc>), + ClonedFrom(VData), +} +/// can be either Data, Mut or ClonedFrom. +/// - any ClonedFrom will point to a Data variant. It can never point to anything else. +/// it will increase the Data's clone count by one on creation and decrease it again on Drop::drop(). +/// - any Mut will eventually point to a ClonedFrom or a Data variant. It can also point to another Mut. +impl VDataInner { + fn to(self) -> VData { + VData(Arc::new(Mutex::new(self))) + } +} +impl VDataEnum { + pub fn to(self) -> VData { + VDataInner::Data(0, Box::new(self)).to() + } +} + +impl VData { + pub fn new_placeholder() -> Self { + VDataEnum::Bool(false).to() + } + /// clones self, retrurning a new instance of self that will always yield the value self had when this function was called. + /// note to dev: since the actual data is stored in VDataEnum, which either clones data or calls clone() (= clone_data()) on further VData, this automatically borrows all child data as immutable too. rust's Drop::drop() implementation (probably) handles everything for us too, so this can be implemented without thinking about recursion. + pub fn clone_data(&self) -> Self { + 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 { + VDataInner::Mut(Arc::new(Mutex::new(self.clone_arc()))).to() + } + fn clone_arc(&self) -> Self { + Self(Arc::clone(&self.0)) + } + pub fn operate_on_data_immut(&self, mut func: F) -> O + where + F: FnOnce(&VDataEnum) -> O, + { + match &*self.0.lock().unwrap() { + VDataInner::Data(_, data) => func(data.as_ref()), + VDataInner::Mut(inner) => inner.lock().unwrap().operate_on_data_immut(func), + VDataInner::ClonedFrom(inner) => inner.operate_on_data_immut(func), + } + } + /// 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 + where + F: FnOnce(&mut VDataEnum) -> O, + { + let (new_val, o) = { + match &mut *self.0.lock().unwrap() { + VDataInner::Data(count, data) => { + if *count == 0 { + (None, func(data.as_mut())) + } else { + #[cfg(debug_assertions)] + eprintln!("Cloning: data should be modified, but was borrowed immutably."); + let mut new_data = data.clone(); + let o = func(new_data.as_mut()); + // *self doesn't modify the ::Data, it instead points the value that wraps it to a new ::Data, leaving the old one as it was. + // for proof: data is untouched, only the new_data is ever modified. + (Some(VDataInner::Data(0, new_data).to()), o) + } + } + VDataInner::Mut(inner) => (None, inner.lock().unwrap().operate_on_data_mut(func)), + VDataInner::ClonedFrom(inner) => (None, inner.operate_on_data_mut(func)), + } + }; + if let Some(nv) = new_val { + *self = nv; + } + o + } + + /// Since operate_on_data_mut can clone, it may be inefficient for just assigning (where we don't care about the previous value, so it doesn't need to be cloned). + /// This is what this function is for. (TODO: actually make it more efficient instead of using operate_on_data_mut) + pub fn assign_data(&mut self, new_data: VDataEnum) { + self.operate_on_data_mut(|d| *d = new_data) + } + /// Assigns the new_data to self. Affects all muts pointing to the same data, but no ClonedFroms. + pub fn assign(&mut self, new: VData) { + self.assign_data(new.inner_cloned()) + // !PROBLEM! If ClonedFrom always has to point to a Data, this may break things! + // match &mut *self.0.lock().unwrap() { + // VDataInner::Data(count, data) => { + // // *self doesn't modify the ::Data, it instead points the value that wraps it to a new ::Data, leaving the old one as it was. + // // for proof: data is untouched. + // *self = new_data; + // } + // VDataInner::Mut(inner) => inner.lock().unwrap().assign(new_data), + // VDataInner::ClonedFrom(inner) => inner.assign(new_data), + // } + } +} +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() { + eprint!("rc: {}", *ref_count); + *ref_count = ref_count.saturating_sub(1); + eprintln!(" -> {}", *ref_count); + } + } + } +} + +impl VData { + /// this will always clone! if a reference or mutable reference is enough, use operate_on_data_* instead! + pub fn inner_cloned(&self) -> VDataEnum { + self.operate_on_data_immut(|v| v.clone()) + } +} + +// - - make VData act like VDataEnum (as if it were real data) - - + +impl Clone for VData { + fn clone(&self) -> Self { + self.clone_data() + } +} +impl VData { + pub fn fmtgs(&self, f: &mut Formatter<'_>, info: Option<&GlobalScriptInfo>) -> fmt::Result { + self.operate_on_data_immut(|v| v.fmtgs(f, info)) + } +} +impl Debug for VData { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.operate_on_data_immut(|v| Debug::fmt(v, f)) + } +} +impl Display for VData { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.operate_on_data_immut(|v| Display::fmt(v, f)) + } +} +impl PartialEq for VData { + fn eq(&self, other: &Self) -> bool { + self.operate_on_data_immut(|a| other.operate_on_data_immut(|b| a == b)) + } +} +impl PartialEq for VData { + fn eq(&self, other: &VDataEnum) -> bool { + self.operate_on_data_immut(|a| a == other) + } +} +impl PartialEq for VDataEnum { + fn eq(&self, other: &VData) -> bool { + other.operate_on_data_immut(|b| self == b) + } +} +impl VData { + pub fn out_single(&self) -> VSingleType { + self.operate_on_data_immut(|v| v.out_single()) + } + pub fn out(&self) -> VType { + self.out_single().to() + } + pub fn noenum(&self) -> Self { + if let Some(v) = self.operate_on_data_immut(|v| v.noenum()) { + v + } else { + self.clone_data() + } + } + pub fn safe_to_share(&self) -> bool { + self.operate_on_data_immut(|v| v.safe_to_share()) + } + pub fn get(&self, i: usize) -> Option { + self.operate_on_data_immut(|v| v.get(i)) + } + pub fn matches(&self) -> Option { + match self.operate_on_data_immut(|v| v.matches()) { + Some(Some(v)) => Some(v), + Some(None) => Some(self.clone_data()), + None => None, + } + } + pub fn deref(&self) -> Option { + self.operate_on_data_immut(|v| v.deref()) + } +} + +// - - VDataEnum - - + impl Clone for VDataEnum { fn clone(&self) -> Self { match self { // exception: don't clone the value AND don't use CoW, // because we want to share the same Arc>. - Self::Reference(r) => Self::Reference(r.clone_mut_assume()), + Self::Reference(r) => Self::Reference(r.clone_mut()), // default impls Self::Bool(b) => Self::Bool(*b), Self::Int(i) => Self::Int(*i), @@ -161,8 +242,8 @@ impl PartialEq for VDataEnum { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Reference(a), Self::Reference(b)) => a == b, - (Self::Reference(a), b) => &a.data().0 == b, - (a, Self::Reference(b)) => a == &b.data().0, + (Self::Reference(a), b) => a == b, + (a, Self::Reference(b)) => a == b, (Self::Bool(a), Self::Bool(b)) => *a == *b, (Self::Int(a), Self::Int(b)) => *a == *b, (Self::Float(a), Self::Float(b)) => *a == *b, @@ -176,55 +257,26 @@ impl PartialEq for VDataEnum { } } -impl VData { - pub fn safe_to_share(&self) -> bool { - self.data().0.safe_to_share() - } - pub fn out(&self) -> VType { - VType { - types: vec![self.out_single()], +impl VDataEnum { + pub fn deref(&self) -> Option { + if let Self::Reference(r) = self { + Some(r.clone_mut()) + } else { + None } } pub fn out_single(&self) -> VSingleType { - match &self.data().0 { - VDataEnum::Bool(..) => VSingleType::Bool, - VDataEnum::Int(..) => VSingleType::Int, - VDataEnum::Float(..) => VSingleType::Float, - VDataEnum::String(..) => VSingleType::String, - VDataEnum::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out()).collect()), - VDataEnum::List(t, _) => VSingleType::List(t.clone()), - VDataEnum::Function(f) => VSingleType::Function(f.input_output_map.clone()), - VDataEnum::Thread(_, o) => VSingleType::Thread(o.clone()), - VDataEnum::Reference(r) => VSingleType::Reference(Box::new(r.out_single())), - VDataEnum::EnumVariant(e, v) => VSingleType::EnumVariant(*e, v.out()), - } - } - pub fn get(&self, i: usize, as_mut: bool) -> Option { - if let Some(mut d) = self.data().0.get(i) { - if as_mut { - d.make_mut(); - } - Some(d) - } else { - None - } - } - pub fn noenum(self) -> Self { - self.inner().noenum() - } -} - -impl VDataEnum { - pub fn to(self) -> VData { - VData { - data: Arc::new(Mutex::new((self, false))), - } - } - pub fn deref(self) -> Option { - if let Self::Reference(r) = self { - Some(r) - } else { - None + match self { + Self::Bool(..) => VSingleType::Bool, + Self::Int(..) => VSingleType::Int, + Self::Float(..) => VSingleType::Float, + Self::String(..) => VSingleType::String, + Self::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out_single().to()).collect()), + Self::List(t, _) => VSingleType::List(t.clone()), + Self::Function(f) => VSingleType::Function(f.input_output_map.clone()), + Self::Thread(_, o) => VSingleType::Thread(o.clone()), + Self::Reference(r) => VSingleType::Reference(Box::new(r.out_single())), + Self::EnumVariant(e, v) => VSingleType::EnumVariant(*e, v.out_single().to()), } } } @@ -240,10 +292,10 @@ impl VDataEnum { Self::Thread(..) | Self::Reference(..) | Self::EnumVariant(..) => false, } } - pub fn noenum(self) -> VData { + pub fn noenum(&self) -> Option { match self { - Self::EnumVariant(_, v) => *v, - v => v.to(), + Self::EnumVariant(_, v) => Some(v.clone_data()), + v => None, } } pub fn get(&self, i: usize) -> Option { @@ -259,8 +311,8 @@ impl VDataEnum { None => None, }, Self::Tuple(v) | Self::List(_, v) => v.get(i).cloned(), - Self::Reference(r) => r.get(i, false), - Self::EnumVariant(_, v) => v.get(i, false), + Self::Reference(r) => r.get(i), + Self::EnumVariant(_, v) => v.get(i), } } pub fn matches_ref_bool(&self) -> bool { @@ -270,18 +322,19 @@ impl VDataEnum { _ => true, } } - pub fn matches(self) -> Option { + /// Some(None) => matches with self + pub fn matches(&self) -> Option> { match self { - VDataEnum::Tuple(mut tuple) => tuple.pop(), + VDataEnum::Tuple(tuple) => tuple.get(0).cloned().map(|v| Some(v)), VDataEnum::Bool(v) => { - if v { - Some(VDataEnum::Bool(v).to()) + if *v { + Some(Some(VDataEnum::Bool(true).to())) } else { None } } VDataEnum::EnumVariant(..) => None, - other => Some(other.to()), + other => Some(None), } } } @@ -460,14 +513,3 @@ impl Display for VDataEnum { self.fmtgs(f, None) } } - -impl VData { - pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result { - self.data().0.fmtgs(f, info) - } -} -impl Display for VData { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - self.fmtgs(f, None) - } -} diff --git a/mers/src/script/val_type.rs b/mers/src/lang/val_type.rs similarity index 100% rename from mers/src/script/val_type.rs rename to mers/src/lang/val_type.rs diff --git a/mers/src/lib.rs b/mers/src/lib.rs index 2597533..f27e562 100755 --- a/mers/src/lib.rs +++ b/mers/src/lib.rs @@ -1,20 +1,20 @@ #![allow(unused)] #![allow(dead_code)] +mod lang; mod libs; mod parsing; -mod script; +pub use lang::{val_data::*, val_type::*}; pub use libs::{ comms::{ByteData, ByteDataA, Message, RespondableMessage}, inlib::MyLib, }; pub use parsing::*; -pub use script::{val_data::*, val_type::*}; pub mod prelude { pub use super::{ - script::{val_data::*, val_type::*}, + lang::{val_data::*, val_type::*}, MyLib, RespondableMessage, }; } diff --git a/mers/src/libs/comms.rs b/mers/src/libs/comms.rs index efd433f..edc1554 100644 --- a/mers/src/libs/comms.rs +++ b/mers/src/libs/comms.rs @@ -1,4 +1,4 @@ -use crate::script::{ +use crate::lang::{ val_data::{VData, VDataEnum}, val_type::{VSingleType, VType}, }; @@ -58,7 +58,7 @@ impl From for Message { // implementations for the message/response pairs pub mod run_function { - use crate::script::val_data::VData; + use crate::lang::val_data::VData; use super::{ByteData, ByteDataA, MessageResponse, RespondableMessage}; @@ -461,7 +461,7 @@ impl ByteData for VSingleType { } impl ByteDataA for VData { fn as_byte_data(&self, vec: &mut Vec) { - self.data().0.as_byte_data(vec) + self.operate_on_data_immut(|v| v.as_byte_data(vec)) } } impl ByteData for VData { diff --git a/mers/src/libs/inlib.rs b/mers/src/libs/inlib.rs index b95c63b..edf77af 100755 --- a/mers/src/libs/inlib.rs +++ b/mers/src/libs/inlib.rs @@ -3,7 +3,7 @@ use std::{ io::{BufRead, Stdin, StdinLock, Stdout, StdoutLock, Write}, }; -use crate::script::{val_data::VData, val_type::VType}; +use crate::lang::{val_data::VData, val_type::VType}; use super::{ comms::{self, ByteData, ByteDataA, Message, MessageResponse, RespondableMessage}, diff --git a/mers/src/libs/mod.rs b/mers/src/libs/mod.rs index 9972cd3..739eeb6 100755 --- a/mers/src/libs/mod.rs +++ b/mers/src/libs/mod.rs @@ -11,13 +11,13 @@ use std::{ }; use crate::{ - libs::comms::{ByteData, ByteDataA}, - parsing::{file::File, parse}, - script::{ + lang::{ global_info::GlobalScriptInfo, val_data::{VData, VDataEnum}, val_type::VType, }, + libs::comms::{ByteData, ByteDataA}, + parsing::{file::File, parse}, }; use self::comms::{MessageResponse, RespondableMessage}; @@ -93,9 +93,9 @@ impl Lib { for (_name, func) in registered_fns.iter_mut() { for (args, out) in func.iter_mut() { for t in args.iter_mut() { - crate::script::to_runnable::stypes(t, &mut ginfo); + crate::lang::to_runnable::stypes(t, &mut ginfo); } - crate::script::to_runnable::stypes(out, &mut ginfo); + crate::lang::to_runnable::stypes(out, &mut ginfo); } } for (name, id) in ginfo.enum_variants { diff --git a/mers/src/main.rs b/mers/src/main.rs index 6b933b2..2a69eec 100755 --- a/mers/src/main.rs +++ b/mers/src/main.rs @@ -6,11 +6,11 @@ use std::{fs, time::Instant}; use notify::Watcher as FsWatcher; mod interactive_mode; +mod lang; mod libs; #[cfg(feature = "nushell_plugin")] mod nushell_plugin; mod parsing; -mod script; mod tutor; fn main() { diff --git a/mers/src/nushell_plugin.rs b/mers/src/nushell_plugin.rs index 57b5cbb..b830020 100755 --- a/mers/src/nushell_plugin.rs +++ b/mers/src/nushell_plugin.rs @@ -4,11 +4,11 @@ use nu_plugin::{serve_plugin, MsgPackSerializer, Plugin}; use nu_protocol::{PluginExample, PluginSignature, ShellError, Span, Spanned, SyntaxShape, Value}; use crate::{ - parsing, - script::{ + lang::{ global_info::GlobalScriptInfo, val_data::{VData, VDataEnum}, }, + parsing, }; pub fn main() { diff --git a/mers/src/parsing/parse.rs b/mers/src/parsing/parse.rs index 6e7f822..8f6d296 100755 --- a/mers/src/parsing/parse.rs +++ b/mers/src/parsing/parse.rs @@ -1,8 +1,7 @@ use std::{fmt::Debug, process::Command, sync::Arc}; use crate::{ - libs, - script::{ + lang::{ code_macro::MacroError, code_parsed::*, code_runnable::RScript, @@ -11,6 +10,7 @@ use crate::{ val_data::VDataEnum, val_type::{VSingleType, VType}, }, + libs, }; use super::file::File; @@ -785,7 +785,7 @@ pub mod implementation { } "!" => { break SStatementEnum::Macro( - match crate::script::code_macro::parse_macro(file) { + match crate::lang::code_macro::parse_macro(file) { Ok(v) => v, Err(e) => { return Err(ParseError { @@ -862,11 +862,17 @@ pub mod implementation { let args = [out].into_iter().chain(args.into_iter()).collect(); SStatementEnum::FunctionCall(func, args).to() } - SStatementEnum::Value(vd) => match &vd.data().0 { - VDataEnum::Int(i) => SStatementEnum::IndexFixed(out, *i as _).to(), - _ => { + SStatementEnum::Value(vd) => { + if let Some(i) = vd.operate_on_data_immut(|v| match v { + VDataEnum::Int(i) => Some(*i as _), + _ => None, + }) { + SStatementEnum::IndexFixed(out, i).to() + } else { return Err(ParseError { - err: ParseErrors::CannotUseFixedIndexingWithThisType(vd.out()), + err: ParseErrors::CannotUseFixedIndexingWithThisType( + vd.out_single().to(), + ), location: err_start_of_wrapper, location_end: Some(err_end_of_wrapper), context: vec![( @@ -876,7 +882,7 @@ pub mod implementation { info: None, }); } - }, + } other => { return Err(ParseError { err: ParseErrors::CannotWrapWithThisStatement(other), @@ -974,6 +980,20 @@ pub mod implementation { ) .to() } + (0..=50, Some('!')) + if matches!( + file.get_char(file.get_pos().current_char_index + 1), + Some('=') + ) => + { + file.next(); + file.next(); + SStatementEnum::FunctionCall( + "ne".to_owned(), + vec![out, parse_statement_adv(file, true, 50)?], + ) + .to() + } (0..=10, Some('=')) => { file.next(); match out.statement.as_mut() { diff --git a/mers/src/tutor/base_comments.rs b/mers/src/tutor/base_comments.rs index 3304d42..b98eefc 100755 --- a/mers/src/tutor/base_comments.rs +++ b/mers/src/tutor/base_comments.rs @@ -1,4 +1,4 @@ -use crate::script::val_data::VDataEnum; +use crate::lang::val_data::VDataEnum; use super::Tutor; @@ -14,7 +14,7 @@ pub fn run(tutor: &mut Tutor) { ", )); loop { - match &tutor.let_user_make_change().run(vec![]).data().0 { + match tutor.let_user_make_change().run(vec![]).inner_cloned() { VDataEnum::Bool(true) => break, other => { tutor.set_status(format!(" - Returned {} instead of true.", other)); diff --git a/mers/src/tutor/base_functions.rs b/mers/src/tutor/base_functions.rs index ecefe85..093cbaa 100755 --- a/mers/src/tutor/base_functions.rs +++ b/mers/src/tutor/base_functions.rs @@ -1,4 +1,4 @@ -use crate::script::val_data::VDataEnum; +use crate::lang::val_data::VDataEnum; use super::Tutor; @@ -35,7 +35,7 @@ mul() ", )); loop { - match &tutor.let_user_make_change().run(vec![]).data().0 { + match tutor.let_user_make_change().run(vec![]).inner_cloned() { VDataEnum::Int(160) => break, other => { tutor.set_status(format!(" - Returned {other} instead of 160")); diff --git a/mers/src/tutor/base_return.rs b/mers/src/tutor/base_return.rs index 0b06252..2197bb0 100755 --- a/mers/src/tutor/base_return.rs +++ b/mers/src/tutor/base_return.rs @@ -1,4 +1,4 @@ -use crate::script::val_data::VDataEnum; +use crate::lang::val_data::VDataEnum; use super::Tutor; @@ -27,7 +27,7 @@ fn compute_sum(a int b int) { ", )); loop { - match &tutor.let_user_make_change().run(vec![]).data().0 { + match tutor.let_user_make_change().run(vec![]).inner_cloned() { VDataEnum::Int(15) => break, other => { tutor.set_status(format!(" - Returned {} instead of 15.", other)); diff --git a/mers/src/tutor/base_types.rs b/mers/src/tutor/base_types.rs index 941e728..1fc7a79 100755 --- a/mers/src/tutor/base_types.rs +++ b/mers/src/tutor/base_types.rs @@ -1,4 +1,4 @@ -use crate::script::val_data::VDataEnum; +use crate::lang::val_data::VDataEnum; use super::Tutor; @@ -54,7 +54,7 @@ switch! words_in_string {} true ")); loop { - match &tutor.let_user_make_change().run(vec![]).data().0 { + match tutor.let_user_make_change().run(vec![]).inner_cloned() { VDataEnum::Tuple(v) if v.is_empty() => { tutor.set_status(format!(" - Returned an empty tuple.")); tutor.update(None); diff --git a/mers/src/tutor/base_values.rs b/mers/src/tutor/base_values.rs index dddba19..4c153b8 100755 --- a/mers/src/tutor/base_values.rs +++ b/mers/src/tutor/base_values.rs @@ -1,4 +1,4 @@ -use crate::script::val_data::VDataEnum; +use crate::lang::val_data::VDataEnum; use super::Tutor; @@ -24,7 +24,7 @@ pub fn run(tutor: &mut Tutor) { // return any enum to return to the menu. ")); loop { - match &tutor.let_user_make_change().run(vec![]).data().0 { + match tutor.let_user_make_change().run(vec![]).inner_cloned() { VDataEnum::EnumVariant(..) => break, other => { tutor.set_status(format!(" - Returned {other} instead of an enum.")); diff --git a/mers/src/tutor/base_variables.rs b/mers/src/tutor/base_variables.rs index a1b01e4..88e45b2 100755 --- a/mers/src/tutor/base_variables.rs +++ b/mers/src/tutor/base_variables.rs @@ -1,4 +1,4 @@ -use crate::script::val_data::VDataEnum; +use crate::lang::val_data::VDataEnum; use super::Tutor; @@ -18,7 +18,7 @@ five_less = sub(my_first_variable 5) // 10 ", )); loop { - match &tutor.let_user_make_change().run(vec![]).data().0 { + match tutor.let_user_make_change().run(vec![]).inner_cloned() { VDataEnum::String(name) if !name.is_empty() => { tutor.i_name = Some(name.to_owned()); break; diff --git a/mers/src/tutor/error_handling.rs b/mers/src/tutor/error_handling.rs index 126abd6..a2ed443 100755 --- a/mers/src/tutor/error_handling.rs +++ b/mers/src/tutor/error_handling.rs @@ -1,4 +1,4 @@ -use crate::script::val_data::VDataEnum; +use crate::lang::val_data::VDataEnum; use super::Tutor; @@ -44,7 +44,7 @@ switch! first { list.get(8) ")); loop { - match &tutor.let_user_make_change().run(vec![]).data().0 { + match tutor.let_user_make_change().run(vec![]).inner_cloned() { VDataEnum::Tuple(v) if !v.is_empty() => { break; } diff --git a/mers/src/tutor/menu.rs b/mers/src/tutor/menu.rs index d98c4fa..3359f95 100755 --- a/mers/src/tutor/menu.rs +++ b/mers/src/tutor/menu.rs @@ -1,4 +1,4 @@ -use crate::script::val_data::VDataEnum; +use crate::lang::val_data::VDataEnum; use super::Tutor; @@ -24,9 +24,9 @@ go_to() ", )); loop { - match &tutor.let_user_make_change().run(vec![]).data().0 { - VDataEnum::Int(pos) if *pos != 0 => { - tutor.current_pos = ((*pos).max(0) as usize).min(MAX_POS); + match tutor.let_user_make_change().run(vec![]).inner_cloned() { + VDataEnum::Int(pos) if pos != 0 => { + tutor.current_pos = (pos.max(0) as usize).min(MAX_POS); match tutor.current_pos { 0 => continue, 1 => super::base_comments::run(&mut tutor), diff --git a/mers/src/tutor/mod.rs b/mers/src/tutor/mod.rs index af80484..97dc94a 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::{ + lang::{code_runnable::RScript, global_info::GSInfo, val_data::VDataEnum}, parsing::{self, file::File, parse::ScriptError}, - script::{code_runnable::RScript, global_info::GSInfo, val_data::VDataEnum}, }; mod base_comments; @@ -45,7 +45,7 @@ false i_name: None, }; loop { - if let VDataEnum::Bool(true) = &tutor.let_user_make_change().run(vec![]).data().0 { + if let VDataEnum::Bool(true) = tutor.let_user_make_change().run(vec![]).inner_cloned() { break; } } diff --git a/mers/tests/test_in_mers.rs b/mers/tests/test_in_mers.rs index e4475b2..288b1dc 100644 --- a/mers/tests/test_in_mers.rs +++ b/mers/tests/test_in_mers.rs @@ -15,7 +15,7 @@ fn run_all() { 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().0, + parse::parse(&mut file).unwrap().run(vec![]).inner_cloned(), VDataEnum::Bool(true) )); } diff --git a/mers_libs/http_requests_v1/src/main.rs b/mers_libs/http_requests_v1/src/main.rs index 4d43ebb..22f7f88 100755 --- a/mers_libs/http_requests_v1/src/main.rs +++ b/mers_libs/http_requests_v1/src/main.rs @@ -57,8 +57,8 @@ fn main() { .unwrap() .1; my_lib.callbacks.run_function.consuming = Some(Box::new(move |msg| { - let url = if let VDataEnum::String(url) = &msg.msg.args[0].data().0 { - url.clone() + let url = if let VDataEnum::String(url) = msg.msg.args[0].inner_cloned() { + url } else { unreachable!() }; diff --git a/when_clone.mers b/when_clone.mers deleted file mode 100644 index 954c3c3..0000000 --- a/when_clone.mers +++ /dev/null @@ -1,8 +0,0 @@ -&a = "value" -&list = ["a" "b" "c" ...] -&elem = &list.get_ref(1) -switch! elem { - [&string] elem.0 = "z" - [] {} -} -list.debug()