completely changed the VData/VDataEnum system: Multiple VData can share one VDataEnum via an Arc<Mutex<VDataEnum>>. If one wants to modify the data, it copies it (Copy on Write). This copying is skipped for shared mutable data (references). This was necessary for the get_ref() function. Expect bugs!

This commit is contained in:
mark 2023-05-11 01:04:15 +02:00
parent ceddb886a9
commit 4efee9e2a2
18 changed files with 535 additions and 298 deletions

8
get_ref.mers Normal file
View File

@ -0,0 +1,8 @@
list = [1 2 3 4 5 6 7 8 9 ...]
second = &list.get_ref(2).assume1()
second.debug()
*second = 24
second.debug()
list.debug()

View File

@ -461,7 +461,7 @@ impl ByteData for VSingleType {
}
impl ByteDataA for VData {
fn as_byte_data(&self, vec: &mut Vec<u8>) {
self.data.as_byte_data(vec)
self.data().0.as_byte_data(vec)
}
}
impl ByteData for VData {
@ -469,9 +469,7 @@ impl ByteData for VData {
where
R: std::io::Read,
{
Ok(Self {
data: ByteData::from_byte_data(data)?,
})
Ok(VDataEnum::from_byte_data(data)?.to())
}
}
impl ByteDataA for VDataEnum {

View File

@ -910,8 +910,8 @@ pub mod implementation {
let args = [out].into_iter().chain(args.into_iter()).collect();
SStatementEnum::FunctionCall(func, args).to()
}
SStatementEnum::Value(vd) => match vd.data {
VDataEnum::Int(i) => SStatementEnum::IndexFixed(out, i as _).to(),
SStatementEnum::Value(vd) => match &vd.data().0 {
VDataEnum::Int(i) => SStatementEnum::IndexFixed(out, *i as _).to(),
_ => {
let mut context = vec![];
if chain_length > 0 {

View File

@ -76,6 +76,7 @@ pub enum BuiltinFunction {
Pop,
Remove,
Get,
GetRef,
Len,
// String
Contains,
@ -138,6 +139,7 @@ impl BuiltinFunction {
"pop" => Self::Pop,
"remove" => Self::Remove,
"get" => Self::Get,
"get_ref" => Self::GetRef,
"len" => Self::Len,
"contains" => Self::Contains,
"starts_with" => Self::StartsWith,
@ -443,7 +445,7 @@ impl BuiltinFunction {
}
}
// TODO! finish this
Self::Get | Self::Len => true,
Self::Get | Self::GetRef | Self::Len => true,
Self::Substring => {
if input.len() >= 2 && input.len() <= 3 {
let (s, start) = (&input[0], &input[1]);
@ -598,6 +600,26 @@ impl BuiltinFunction {
unreachable!("get, pop or remove called without args")
}
}
Self::GetRef => {
if let Some(v) = input.first() {
VType {
types: vec![
VSingleType::Tuple(vec![]),
VSingleType::Tuple(vec![{
let mut v = v.get_any(info).expect("cannot use get on this type");
v.types = v
.types
.into_iter()
.map(|v| VSingleType::Reference(Box::new(v)))
.collect();
v
}]),
],
}
} else {
unreachable!("get, pop or remove called without args")
}
}
Self::Exit => VType { types: vec![] }, // doesn't return
Self::FsList => VType {
types: vec![
@ -726,67 +748,87 @@ impl BuiltinFunction {
},
}
}
pub fn run(
&self,
args: &Vec<RStatement>,
vars: &Vec<Arc<Mutex<VData>>>,
info: &GSInfo,
) -> VData {
pub fn run(&self, args: &Vec<RStatement>, vars: &mut Vec<VData>, info: &GSInfo) -> VData {
match self {
Self::Assume1 => match args[0].run(vars, info).data {
VDataEnum::Tuple(mut v) => {
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
} else {
panic!(
"ASSUMPTION FAILED: assume1 :: {}",
if args.len() > 1 {
if let VDataEnum::String(v) = args[1].run(vars, info).data {
v
let msg = if args.len() > 1 {
let a1 = args[1].run(vars, info);
let a1 = a1.data();
if let VDataEnum::String(v) = &a1.0 {
Some(v.to_owned())
} else {
String::new()
None
}
} else {
String::new()
},
);
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
}
}
v => v.to(),
},
Self::AssumeNoEnum => {
let data = args[0].run(vars, info);
match data.data {
VDataEnum::EnumVariant(..) => panic!(
"ASSUMPTION FAILED: assume_no_enum :: found {} :: {}",
data.gsi(info.clone()),
if args.len() > 1 {
if let VDataEnum::String(v) = args[1].run(vars, info).data {
v
let msg = if args.len() > 1 {
if let VDataEnum::String(v) = args[1].run(vars, info).inner() {
Some(v.to_owned())
} 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()
}
} else {
String::new()
)
}
_ => {
drop(a0d);
a0
}
),
d => d.to(),
}
}
Self::NoEnum => args[0].run(vars, info).noenum(),
Self::Matches => match args[0].run(vars, info).data.matches() {
Self::Matches => match args[0].run(vars, info).inner().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 {
r.lock().unwrap().clone()
if let VDataEnum::Reference(r) = &args[0].run(vars, info).data().0 {
r.clone()
} else {
unreachable!()
}
}
BuiltinFunction::Print => {
if let VDataEnum::String(arg) = args[0].run(vars, info).data {
if let VDataEnum::String(arg) = &args[0].run(vars, info).data().0 {
print!("{}", arg);
VDataEnum::Tuple(vec![]).to()
} else {
@ -794,7 +836,7 @@ impl BuiltinFunction {
}
}
BuiltinFunction::Println => {
if let VDataEnum::String(arg) = args[0].run(vars, info).data {
if let VDataEnum::String(arg) = &args[0].run(vars, info).data().0 {
#[cfg(not(feature = "nushell_plugin"))]
println!("{}", arg);
#[cfg(feature = "nushell_plugin")]
@ -831,13 +873,13 @@ impl BuiltinFunction {
VDataEnum::String(args[0].run(vars, info).gsi(info.clone()).to_string()).to()
}
BuiltinFunction::Format => {
if let VDataEnum::String(mut text) = args.first().unwrap().run(vars, info).data {
if let VDataEnum::String(mut text) = args.first().unwrap().run(vars, info).inner() {
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 {
if let VDataEnum::String(v) = &arg.run(vars, info).data().0 {
v
} else {
unreachable!()
@ -852,7 +894,7 @@ impl BuiltinFunction {
}
BuiltinFunction::ParseInt => {
if args.len() == 1 {
if let VDataEnum::String(s) = args[0].run(vars, info).data {
if let VDataEnum::String(s) = &args[0].run(vars, info).data().0 {
if let Ok(s) = s.parse() {
VDataEnum::Int(s).to()
} else {
@ -867,7 +909,7 @@ impl BuiltinFunction {
}
BuiltinFunction::ParseFloat => {
if args.len() == 1 {
if let VDataEnum::String(s) = args[0].run(vars, info).data {
if let VDataEnum::String(s) = &args[0].run(vars, info).data().0 {
if let Ok(s) = s.parse() {
VDataEnum::Float(s).to()
} else {
@ -882,13 +924,13 @@ impl BuiltinFunction {
}
BuiltinFunction::Run => {
if args.len() >= 1 {
if let VDataEnum::Function(f) = args[0].run(vars, info).data {
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].lock().unwrap() = val;
vars[*var] = val;
}
f.run(vars, info)
} else {
@ -900,7 +942,7 @@ impl BuiltinFunction {
}
BuiltinFunction::Thread => {
if args.len() >= 1 {
if let VDataEnum::Function(f) = args[0].run(vars, info).data {
if let VDataEnum::Function(f) = args[0].run(vars, info).inner() {
if f.inputs.len() != args.len() - 1 {
unreachable!()
}
@ -910,13 +952,13 @@ impl BuiltinFunction {
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] = Arc::new(Mutex::new(val));
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(&thread_vars, &libs)
f.run(&mut thread_vars, &libs)
}))
.to(),
out_type,
@ -931,7 +973,7 @@ impl BuiltinFunction {
}
BuiltinFunction::Await => {
if args.len() == 1 {
if let VDataEnum::Thread(t, _) = args[0].run(vars, info).data {
if let VDataEnum::Thread(t, _) = &args[0].run(vars, info).data().0 {
t.get()
} else {
unreachable!()
@ -942,9 +984,9 @@ impl BuiltinFunction {
}
BuiltinFunction::Sleep => {
if args.len() == 1 {
match args[0].run(vars, info).data {
VDataEnum::Int(v) => std::thread::sleep(Duration::from_secs(v as _)),
VDataEnum::Float(v) => std::thread::sleep(Duration::from_secs_f64(v)),
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()
@ -954,8 +996,8 @@ impl BuiltinFunction {
}
Self::Exit => {
if let Some(s) = args.first() {
if let VDataEnum::Int(v) = s.run(vars, info).data {
std::process::exit(v as _);
if let VDataEnum::Int(v) = &s.run(vars, info).data().0 {
std::process::exit(*v as _);
} else {
std::process::exit(1);
}
@ -965,7 +1007,7 @@ impl BuiltinFunction {
}
Self::FsList => {
if args.len() > 0 {
if let VDataEnum::String(path) = args[0].run(vars, info).data {
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")
}
@ -1003,7 +1045,7 @@ impl BuiltinFunction {
}
Self::FsRead => {
if args.len() > 0 {
if let VDataEnum::String(path) = args[0].run(vars, info).data {
if let VDataEnum::String(path) = &args[0].run(vars, info).data().0 {
match std::fs::read(path) {
Ok(data) => VDataEnum::List(
VSingleType::Int.into(),
@ -1027,9 +1069,10 @@ impl BuiltinFunction {
}
Self::FsWrite => {
if args.len() > 1 {
if let (VDataEnum::String(path), VDataEnum::List(_, data)) =
(args[0].run(vars, info).data, args[1].run(vars, info).data)
{
if let (VDataEnum::String(path), VDataEnum::List(_, data)) = (
&args[0].run(vars, info).data().0,
&args[1].run(vars, info).data().0,
) {
if let Some(bytes) = vdata_to_bytes(&data) {
let file_path: PathBuf = path.into();
if let Some(p) = file_path.parent() {
@ -1057,7 +1100,7 @@ impl BuiltinFunction {
}
Self::BytesToString => {
if args.len() == 1 {
if let VDataEnum::List(_, byte_data) = args[0].run(vars, info).data {
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(),
@ -1092,7 +1135,7 @@ impl BuiltinFunction {
}
Self::StringToBytes => {
if args.len() == 1 {
if let VDataEnum::String(s) = args[0].run(vars, info).data {
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(),
@ -1107,12 +1150,12 @@ impl BuiltinFunction {
}
Self::RunCommand | Self::RunCommandGetBytes => {
if args.len() > 0 {
if let VDataEnum::String(s) = args[0].run(vars, info).data {
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 {
if let VDataEnum::List(_, args) = &args[1].run(vars, info).data().0 {
for arg in args {
if let VDataEnum::String(v) = arg.data {
if let VDataEnum::String(v) = &arg.data().0 {
command.arg(v);
} else {
unreachable!("run_command second arg not [string].")
@ -1172,19 +1215,19 @@ impl BuiltinFunction {
}
}
Self::Not => {
if let VDataEnum::Bool(v) = args[0].run(vars, info).data {
if let VDataEnum::Bool(v) = &args[0].run(vars, info).data().0 {
VDataEnum::Bool(!v).to()
} else {
unreachable!()
}
}
Self::And => {
if let VDataEnum::Bool(a) = args[0].run(vars, info).data {
if a == false {
if let VDataEnum::Bool(a) = &args[0].run(vars, info).data().0 {
if *a == false {
VDataEnum::Bool(false).to()
} else {
if let VDataEnum::Bool(b) = args[1].run(vars, info).data {
VDataEnum::Bool(b).to()
if let VDataEnum::Bool(b) = &args[1].run(vars, info).data().0 {
VDataEnum::Bool(*b).to()
} else {
unreachable!()
}
@ -1194,12 +1237,12 @@ impl BuiltinFunction {
}
}
Self::Or => {
if let VDataEnum::Bool(a) = args[0].run(vars, info).data {
if a == true {
if let VDataEnum::Bool(a) = &args[0].run(vars, info).data().0 {
if *a == true {
VDataEnum::Bool(true).to()
} else {
if let VDataEnum::Bool(b) = args[1].run(vars, info).data {
VDataEnum::Bool(b).to()
if let VDataEnum::Bool(b) = &args[1].run(vars, info).data().0 {
VDataEnum::Bool(*b).to()
} else {
unreachable!()
}
@ -1210,7 +1253,10 @@ impl BuiltinFunction {
}
Self::Add => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
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()
@ -1231,13 +1277,16 @@ impl BuiltinFunction {
}
Self::Sub => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
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 as f64 - *b).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Float(a - b as f64).to()
VDataEnum::Float(*a - *b as f64).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a - b).to(),
_ => unreachable!("sub: not a number"),
@ -1248,13 +1297,16 @@ impl BuiltinFunction {
}
Self::Mul => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
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 as f64 * b).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Float(a * b as f64).to()
VDataEnum::Float(a * *b as f64).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a * b).to(),
_ => unreachable!("mul: not a number"),
@ -1265,13 +1317,16 @@ impl BuiltinFunction {
}
Self::Div => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
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 as f64 / b).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Float(a / b as f64).to()
VDataEnum::Float(a / *b as f64).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a / b).to(),
_ => unreachable!("div: not a number"),
@ -1282,13 +1337,16 @@ impl BuiltinFunction {
}
Self::Mod => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
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 as f64 % b).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Float(a % b as f64).to()
VDataEnum::Float(a % *b as f64).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a % b).to(),
_ => unreachable!("mod: not a number"),
@ -1299,23 +1357,26 @@ impl BuiltinFunction {
}
Self::Pow => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(if b == 0 {
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 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 as f64).powf(*b)).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Float(a.powi(b as _)).to()
VDataEnum::Float((*a).powi(*b as _)).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => {
VDataEnum::Float(a.powf(b)).to()
VDataEnum::Float((*a).powf(*b)).to()
}
_ => unreachable!("pow: not a number"),
}
@ -1332,15 +1393,18 @@ impl BuiltinFunction {
}
Self::Gt => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a > b).to(),
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::Bool(*a as f64 > *b).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Bool(a > b as f64).to()
VDataEnum::Bool(*a > *b as f64).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(a > b).to(),
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(*a > *b).to(),
_ => unreachable!("gt: not a number"),
}
} else {
@ -1349,15 +1413,18 @@ impl BuiltinFunction {
}
Self::Lt => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a < b).to(),
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::Bool((*a as f64) < *b).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Bool(a < b as f64).to()
VDataEnum::Bool(*a < *b as f64).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(a < b).to(),
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(*a < *b).to(),
_ => unreachable!("lt: not a number"),
}
} else {
@ -1366,15 +1433,20 @@ impl BuiltinFunction {
}
Self::Gtoe => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a >= b).to(),
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::Bool(*a as f64 >= *b).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Bool(a >= b as f64).to()
VDataEnum::Bool(*a >= *b as f64).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => {
VDataEnum::Bool(*a >= *b).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(a >= b).to(),
_ => unreachable!("gtoe: not a number"),
}
} else {
@ -1383,15 +1455,20 @@ impl BuiltinFunction {
}
Self::Ltoe => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a <= b).to(),
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::Bool(*a as f64 <= *b).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Bool(a <= b as f64).to()
VDataEnum::Bool(*a <= *b as f64).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => {
VDataEnum::Bool(*a <= *b).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(a <= b).to(),
_ => unreachable!("ltoe: not a number"),
}
} else {
@ -1400,16 +1477,19 @@ impl BuiltinFunction {
}
Self::Min => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a.min(b)).to(),
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 as f64).min(*b)).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Float(a.min(b as f64)).to()
VDataEnum::Float((*a).min(*b as f64)).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => {
VDataEnum::Float(a.min(b)).to()
VDataEnum::Float((*a).min(*b)).to()
}
_ => unreachable!("min: not a number"),
}
@ -1419,16 +1499,19 @@ impl BuiltinFunction {
}
Self::Max => {
if args.len() == 2 {
match (args[0].run(vars, info).data, args[1].run(vars, info).data) {
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a.max(b)).to(),
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 as f64).max(*b)).to()
}
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
VDataEnum::Float(a.max(b as f64)).to()
VDataEnum::Float((*a).max(*b as f64)).to()
}
(VDataEnum::Float(a), VDataEnum::Float(b)) => {
VDataEnum::Float(a.max(b)).to()
VDataEnum::Float((*a).max(*b)).to()
}
_ => unreachable!("max: not a number"),
}
@ -1438,8 +1521,9 @@ impl BuiltinFunction {
}
Self::Push => {
if args.len() == 2 {
if let VDataEnum::Reference(v) = args[0].run(vars, info).data {
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
// 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::Tuple(vec![]).to()
@ -1452,11 +1536,13 @@ impl BuiltinFunction {
}
Self::Insert => {
if args.len() == 3 {
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) =
(args[0].run(vars, info).data, args[2].run(vars, info).data)
{
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
v.insert(i as _, args[1].run(vars, info));
// 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));
}
VDataEnum::Tuple(vec![]).to()
} else {
@ -1468,8 +1554,9 @@ impl BuiltinFunction {
}
Self::Pop => {
if args.len() == 1 {
if let VDataEnum::Reference(v) = args[0].run(vars, info).data {
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
// 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 {
if let Some(v) = v.pop() {
VDataEnum::Tuple(vec![v])
} else {
@ -1488,12 +1575,14 @@ impl BuiltinFunction {
}
Self::Remove => {
if args.len() == 2 {
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) =
(args[0].run(vars, info).data, args[1].run(vars, info).data)
{
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
if v.len() > i as _ && i >= 0 {
let v = v.remove(i as _);
// 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::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()
} else {
VDataEnum::Tuple(vec![]).to()
@ -1510,21 +1599,22 @@ impl BuiltinFunction {
}
Self::Get => {
if args.len() == 2 {
if let (container, VDataEnum::Int(i)) =
(args[0].run(vars, info).data, args[1].run(vars, info).data)
{
if i >= 0 {
if let (container, VDataEnum::Int(i)) = (
&args[0].run(vars, info).data().0,
&args[1].run(vars, info).data().0,
) {
if *i >= 0 {
match match container {
VDataEnum::Reference(v) => match &v.lock().unwrap().data {
VDataEnum::Reference(v) => match &v.data().0 {
VDataEnum::List(_, v) | VDataEnum::Tuple(v) => {
v.get(i as usize).map(|v| v.clone())
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())
v.get(*i as usize).map(|v| v.clone())
}
_ => unreachable!("get: not a reference/list/tuple"),
} {
@ -1541,9 +1631,40 @@ impl BuiltinFunction {
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,
) {
if *i >= 0 {
// we can get mutably because this is the content of a reference
match match &mut container.data().0 {
VDataEnum::List(_, v) | VDataEnum::Tuple(v) => {
if let Some(v) = v.get_mut(*i as usize) {
Some(VDataEnum::Reference(v.clone_mut()).to())
} else {
None
}
}
_ => unreachable!("get: not a reference/list/tuple"),
} {
Some(v) => VDataEnum::Tuple(vec![v]).to(),
None => VDataEnum::Tuple(vec![]).to(),
}
} else {
VDataEnum::Tuple(vec![]).to()
}
} 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 {
VDataEnum::Int(match &args[0].run(vars, info).data().0 {
VDataEnum::String(v) => v.len(),
VDataEnum::Tuple(v) => v.len(),
VDataEnum::List(_, v) => v.len(),
@ -1556,8 +1677,8 @@ impl BuiltinFunction {
}
Self::Contains => {
if args.len() == 2 {
if let VDataEnum::String(a1) = args[0].run(vars, info).data {
if let VDataEnum::String(a2) = args[1].run(vars, info).data {
if let VDataEnum::String(a1) = &args[0].run(vars, info).data().0 {
if let VDataEnum::String(a2) = &args[1].run(vars, info).data().0 {
VDataEnum::Bool(a1.contains(a2.as_str())).to()
} else {
unreachable!()
@ -1571,8 +1692,8 @@ impl BuiltinFunction {
}
Self::StartsWith => {
if args.len() == 2 {
if let VDataEnum::String(a1) = args[0].run(vars, info).data {
if let VDataEnum::String(a2) = args[1].run(vars, info).data {
if let VDataEnum::String(a1) = &args[0].run(vars, info).data().0 {
if let VDataEnum::String(a2) = &args[1].run(vars, info).data().0 {
VDataEnum::Bool(a1.starts_with(a2.as_str())).to()
} else {
unreachable!()
@ -1586,8 +1707,8 @@ impl BuiltinFunction {
}
Self::EndsWith => {
if args.len() == 2 {
if let VDataEnum::String(a1) = args[0].run(vars, info).data {
if let VDataEnum::String(a2) = args[1].run(vars, info).data {
if let VDataEnum::String(a1) = &args[0].run(vars, info).data().0 {
if let VDataEnum::String(a2) = &args[1].run(vars, info).data().0 {
VDataEnum::Bool(a1.ends_with(a2.as_str())).to()
} else {
unreachable!()
@ -1622,41 +1743,38 @@ impl BuiltinFunction {
VDataEnum::Tuple(vec![]).to()
}
}
match (find_in.data, pat.data) {
(VDataEnum::String(a), VDataEnum::String(b)) => find(&a, &b),
(VDataEnum::String(a), VDataEnum::Reference(b)) => {
match &b.lock().unwrap().data {
VDataEnum::String(b) => find(&a, b),
let o = match (&find_in.data().0, &pat.data().0) {
(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.lock().unwrap().data {
VDataEnum::String(a) => find(a, &b),
},
(VDataEnum::Reference(a), VDataEnum::String(b)) => match &a.data().0 {
VDataEnum::String(a) => find(a, b),
_ => unreachable!(),
}
}
},
(VDataEnum::Reference(a), VDataEnum::Reference(b)) => {
if Arc::ptr_eq(&a, &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.lock().unwrap().data, &b.lock().unwrap().data) {
match (&a.data().0, &b.data().0) {
(VDataEnum::String(a), VDataEnum::String(b)) => find(a, b),
_ => unreachable!(),
}
}
}
_ => unreachable!(),
}
};
o
} else {
unreachable!()
}
}
Self::Trim => {
if args.len() == 1 {
if let VDataEnum::String(a) = args[0].run(vars, info).data {
if let VDataEnum::String(a) = &args[0].run(vars, info).data().0 {
VDataEnum::String(a.trim().to_string()).to()
} else {
unreachable!()
@ -1667,18 +1785,18 @@ impl BuiltinFunction {
}
Self::Substring => {
if args.len() >= 2 {
if let VDataEnum::String(a) = args[0].run(vars, info).data {
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 {
left
let left = if let VDataEnum::Int(left) = &args[1].run(vars, info).data().0 {
*left
} else {
unreachable!()
};
let len = if args.len() == 3 {
if let VDataEnum::Int(len) = args[2].run(vars, info).data {
Some(len)
if let VDataEnum::Int(len) = &args[2].run(vars, info).data().0 {
Some(*len)
} else {
unreachable!()
}
@ -1714,20 +1832,21 @@ impl BuiltinFunction {
}
Self::Replace => {
if let (VDataEnum::String(a), VDataEnum::String(b), VDataEnum::String(c)) = (
args[0].run(vars, info).data,
args[1].run(vars, info).data,
args[2].run(vars, info).data,
&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()
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, args[1].run(vars, info).data)
{
if let (VDataEnum::String(a), VDataEnum::String(regex)) = (
&args[0].run(vars, info).data().0,
&args[1].run(vars, info).data().0,
) {
match regex::Regex::new(regex.as_str()) {
Ok(regex) => VDataEnum::List(
VSingleType::String.to(),
@ -1757,9 +1876,9 @@ impl BuiltinFunction {
fn vdata_to_bytes(vd: &Vec<VData>) -> Option<Vec<u8>> {
let mut bytes = Vec::with_capacity(vd.len());
for b in vd {
if let VDataEnum::Int(b) = b.data {
bytes.push(if 0 <= b && b <= u8::MAX as isize {
b as u8
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
} else {

View File

@ -8,17 +8,12 @@ use super::{
val_type::{VSingleType, VType},
};
type Am<T> = Arc<Mutex<T>>;
fn am<T>(i: T) -> Am<T> {
Arc::new(Mutex::new(i))
}
#[derive(Clone, Debug)]
pub struct RBlock {
pub statements: Vec<RStatement>,
}
impl RBlock {
pub fn run(&self, vars: &Vec<Am<VData>>, info: &GSInfo) -> VData {
pub fn run(&self, vars: &mut Vec<VData>, info: &GSInfo) -> VData {
let mut last = None;
for statement in &self.statements {
last = Some(statement.run(vars, info));
@ -48,7 +43,7 @@ pub struct RFunction {
pub block: RBlock,
}
impl RFunction {
pub fn run(&self, vars: &Vec<Am<VData>>, info: &GSInfo) -> VData {
pub fn run(&self, vars: &mut Vec<VData>, info: &GSInfo) -> VData {
self.block.run(vars, info)
}
pub fn out(&self, input_types: &Vec<VSingleType>) -> VType {
@ -91,19 +86,22 @@ pub struct RStatement {
pub force_output_type: Option<VType>,
}
impl RStatement {
pub fn run(&self, vars: &Vec<Am<VData>>, info: &GSInfo) -> VData {
pub fn run(&self, vars: &mut Vec<VData>, info: &GSInfo) -> VData {
let out = self.statement.run(vars, info);
if let Some((v, derefs)) = self.output_to {
let mut val = vars[v].clone();
for _ in 0..derefs {
let v = if let VDataEnum::Reference(v) = &val.lock().unwrap().data {
v.clone()
let mut val = dereference_n(&mut vars[v], derefs);
fn dereference_n(d: &mut VData, n: usize) -> VData {
if n > 0 {
if let VDataEnum::Reference(v) = &mut d.data.lock().unwrap().0 {
dereference_n(v, n - 1)
} else {
unreachable!("dereferencing something that isn't a reference in assignment")
};
val = v;
}
*val.lock().unwrap() = out;
} else {
d.clone_mut()
}
}
val.assign(out.inner());
VDataEnum::Tuple(vec![]).to()
} else {
out
@ -142,7 +140,7 @@ pub enum RStatementEnum {
EnumVariant(usize, RStatement),
}
impl RStatementEnum {
pub fn run(&self, vars: &Vec<Am<VData>>, info: &GSInfo) -> VData {
pub fn run(&self, vars: &mut Vec<VData>, info: &GSInfo) -> VData {
match self {
Self::Value(v) => v.clone(),
Self::Tuple(v) => {
@ -164,14 +162,16 @@ impl RStatementEnum {
}
Self::Variable(v, _, is_ref) => {
if *is_ref {
VDataEnum::Reference(vars[*v].clone()).to()
// shared mutability (clone_mut)
VDataEnum::Reference(vars[*v].clone_mut()).to()
} else {
vars[*v].lock().unwrap().clone()
// Copy on Write (clone)
vars[*v].clone()
}
}
Self::FunctionCall(func, args) => {
for (i, input) in func.inputs.iter().enumerate() {
*vars[*input].lock().unwrap() = args[i].run(vars, info);
vars[*input] = args[i].run(vars, info);
}
func.run(vars, info)
}
@ -180,8 +180,8 @@ impl RStatementEnum {
.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 {
if v {
if let VDataEnum::Bool(v) = &c.run(vars, info).data().0 {
if *v {
t.run(vars, info)
} else {
if let Some(e) = e {
@ -196,7 +196,7 @@ impl RStatementEnum {
}
Self::Loop(c) => loop {
// loops will break if the value matches.
if let Some(break_val) = c.run(vars, info).data.matches() {
if let Some(break_val) = c.run(vars, info).inner().matches() {
break break_val;
}
},
@ -204,17 +204,17 @@ impl RStatementEnum {
// 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<Arc<Mutex<VData>>>, c| {
vars[*v] = Arc::new(Mutex::new(c));
b.run(&vars, info)
let in_loop = |vars: &mut Vec<VData>, c| {
vars[*v] = c;
b.run(vars, info)
};
let mut oval = VDataEnum::Tuple(vec![]).to();
match c.data {
match &c.data().0 {
VDataEnum::Int(v) => {
for i in 0..v {
for i in 0..*v {
if let Some(v) =
in_loop(&mut vars, VDataEnum::Int(i).to()).data.matches()
in_loop(&mut vars, VDataEnum::Int(i).to()).inner().matches()
{
oval = v;
break;
@ -225,7 +225,7 @@ impl RStatementEnum {
for ch in v.chars() {
if let Some(v) =
in_loop(&mut vars, VDataEnum::String(ch.to_string()).to())
.data
.inner()
.matches()
{
oval = v;
@ -235,15 +235,15 @@ impl RStatementEnum {
}
VDataEnum::Tuple(v) | VDataEnum::List(_, v) => {
for v in v {
if let Some(v) = in_loop(&mut vars, v).data.matches() {
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(&vars, info).data.matches() {
if let Some(v) = in_loop(&mut vars, v).data.matches() {
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;
}
@ -270,10 +270,10 @@ 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).data.matches() {
let og = { std::mem::replace(&mut *vars[*match_on].lock().unwrap(), v) };
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].lock().unwrap() = og;
vars[*match_on] = og;
break 'm res;
}
}
@ -377,17 +377,19 @@ impl RScript {
}
pub fn run(&self, args: Vec<String>) -> VData {
let mut vars = Vec::with_capacity(self.info.vars);
vars.push(am(VDataEnum::List(
vars.push(
VDataEnum::List(
VSingleType::String.into(),
args.into_iter()
.map(|v| VDataEnum::String(v).to())
.collect(),
)
.to()));
.to(),
);
for _i in 1..self.info.vars {
vars.push(am(VDataEnum::Tuple(vec![]).to()));
vars.push(VDataEnum::Tuple(vec![]).to());
}
self.main.run(&vars, &self.info)
self.main.run(&mut vars, &self.info)
}
pub fn info(&self) -> &GSInfo {
&self.info

View File

@ -75,7 +75,7 @@ impl ToRunnableError {
Self::CannotDereferenceTypeNTimes(og_type, derefs_wanted, last_valid_type) => {
write!(f, "Cannot dereference type ")?;
og_type.fmtgs(f, info)?;
write!(f, "{derefs_wanted} times (stopped at ")?;
write!(f, " {derefs_wanted} times (stopped at ")?;
last_valid_type.fmtgs(f, info);
write!(f, ")")?;
Ok(())

View File

@ -5,16 +5,101 @@ use std::{
use super::{
code_runnable::RFunction,
global_info::{GlobalScriptInfo, GSInfo},
global_info::{GSInfo, GlobalScriptInfo},
val_type::{VSingleType, VType},
};
#[derive(Clone, Debug, PartialEq)]
pub struct VData {
pub data: VDataEnum,
/// (_, mutable) - if false, behave as CopyOnWrite.
pub data: Arc<Mutex<(VDataEnum, bool)>>,
}
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;
}
}
*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 {
self.data().0.clone()
}
/// ensures self is mutable, then returns a new instance of VData that is also mutable and uses the same Arc<Mutex<_>>.
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.
self.clone_mut_assume()
}
/// like clone_mut, but assumes self is already mutable, and therefor does not need to mutate self
/// as the Arc<Mutex<_>> 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.lock().unwrap();
if !s.1 {
*s = (s.0.clone(), 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();
// set to immutable, locking the data as-is.
d.1 = false;
// then return the same arc (-> avoid cloning)
Self {
data: Arc::clone(&self.data),
}
}
}
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(Clone, Debug)]
#[derive(Debug)]
pub enum VDataEnum {
Bool(bool),
Int(isize),
@ -24,15 +109,34 @@ pub enum VDataEnum {
List(VType, Vec<VData>),
Function(RFunction),
Thread(thread::VDataThread, VType),
Reference(Arc<Mutex<VData>>),
Reference(VData),
EnumVariant(usize, Box<VData>),
}
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<Mutex<_>>.
Self::Reference(r) => Self::Reference(r.clone_mut_assume()),
// default impls
Self::Bool(b) => Self::Bool(*b),
Self::Int(i) => Self::Int(*i),
Self::Float(f) => Self::Float(*f),
Self::String(s) => Self::String(s.clone()),
Self::Tuple(v) => Self::Tuple(v.clone()),
Self::List(t, v) => Self::List(t.clone(), v.clone()),
Self::Function(f) => Self::Function(f.clone()),
Self::Thread(th, ty) => Self::Thread(th.clone(), ty.clone()),
Self::EnumVariant(v, d) => Self::EnumVariant(v.clone(), d.clone()),
}
}
}
impl PartialEq for VDataEnum {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Reference(a), Self::Reference(b)) => *a.lock().unwrap() == *b.lock().unwrap(),
(Self::Reference(a), b) => a.lock().unwrap().data == *b,
(a, Self::Reference(b)) => *a == b.lock().unwrap().data,
(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::Bool(a), Self::Bool(b)) => *a == *b,
(Self::Int(a), Self::Int(b)) => *a == *b,
(Self::Float(a), Self::Float(b)) => *a == *b,
@ -48,7 +152,7 @@ impl PartialEq for VDataEnum {
impl VData {
pub fn safe_to_share(&self) -> bool {
self.data.safe_to_share()
self.data().0.safe_to_share()
}
pub fn out(&self) -> VType {
VType {
@ -56,7 +160,7 @@ impl VData {
}
}
pub fn out_single(&self) -> VSingleType {
match &self.data {
match &self.data().0 {
VDataEnum::Bool(..) => VSingleType::Bool,
VDataEnum::Int(..) => VSingleType::Int,
VDataEnum::Float(..) => VSingleType::Float,
@ -65,21 +169,23 @@ impl VData {
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) => r.lock().unwrap().out_single(),
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) -> Option<Self> {
self.data.get(i)
self.data().0.get(i)
}
pub fn noenum(self) -> Self {
self.data.noenum()
self.inner().noenum()
}
}
impl VDataEnum {
pub fn to(self) -> VData {
VData { data: self }
VData {
data: Arc::new(Mutex::new((self, true))),
}
}
}
@ -113,7 +219,7 @@ impl VDataEnum {
None => None,
},
Self::Tuple(v) | Self::List(_, v) => v.get(i).cloned(),
Self::Reference(r) => r.lock().unwrap().get(i),
Self::Reference(r) => r.get(i),
Self::EnumVariant(_, v) => v.get(i),
}
}
@ -286,13 +392,17 @@ impl VDataEnum {
Self::Thread(..) => write!(f, "[TODO] THREAD"),
Self::Reference(inner) => {
write!(f, "&")?;
inner.lock().unwrap().fmtgs(f, info)
inner.fmtgs(f, info)
}
Self::EnumVariant(variant, inner) => {
if let Some(name) = if let Some(info) = info {
info.enum_variants
.iter()
.find_map(|(name, id)| if id == variant { Some(name) } else { None })
info.enum_variants.iter().find_map(|(name, id)| {
if id == variant {
Some(name)
} else {
None
}
})
} else {
None
} {
@ -313,7 +423,7 @@ impl Display for VDataEnum {
impl VData {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result {
self.data.fmtgs(f, info)
self.data().0.fmtgs(f, info)
}
}
impl Display for VData {

View File

@ -14,7 +14,7 @@ pub fn run(tutor: &mut Tutor) {
",
));
loop {
match tutor.let_user_make_change().run(vec![]).data {
match &tutor.let_user_make_change().run(vec![]).data().0 {
VDataEnum::Bool(true) => break,
other => {
tutor.set_status(format!(" - Returned {} instead of true.", other));

View File

@ -35,7 +35,7 @@ mul()
",
));
loop {
match tutor.let_user_make_change().run(vec![]).data {
match &tutor.let_user_make_change().run(vec![]).data().0 {
VDataEnum::Int(160) => break,
other => {
tutor.set_status(format!(" - Returned {other} instead of 160"));

View File

@ -27,7 +27,7 @@ fn compute_sum(a int b int) {
",
));
loop {
match tutor.let_user_make_change().run(vec![]).data {
match &tutor.let_user_make_change().run(vec![]).data().0 {
VDataEnum::Int(15) => break,
other => {
tutor.set_status(format!(" - Returned {} instead of 15.", other));

View File

@ -54,7 +54,7 @@ switch! words_in_string {}
true
"));
loop {
match tutor.let_user_make_change().run(vec![]).data {
match &tutor.let_user_make_change().run(vec![]).data().0 {
VDataEnum::Tuple(v) if v.is_empty() => {
tutor.set_status(format!(" - Returned an empty tuple."));
tutor.update(None);

View File

@ -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 {
match &tutor.let_user_make_change().run(vec![]).data().0 {
VDataEnum::EnumVariant(..) => break,
other => {
tutor.set_status(format!(" - Returned {other} instead of an enum."));

View File

@ -18,9 +18,9 @@ five_less = sub(my_first_variable 5) // 10
",
));
loop {
match tutor.let_user_make_change().run(vec![]).data {
match &tutor.let_user_make_change().run(vec![]).data().0 {
VDataEnum::String(name) if !name.is_empty() => {
tutor.i_name = Some(name);
tutor.i_name = Some(name.to_owned());
break;
}
VDataEnum::String(_) => {

View File

@ -44,7 +44,7 @@ switch! first {
list.get(8)
"));
loop {
match tutor.let_user_make_change().run(vec![]).data {
match &tutor.let_user_make_change().run(vec![]).data().0 {
VDataEnum::Tuple(v) if !v.is_empty() => {
break;
}

View File

@ -24,9 +24,9 @@ go_to()
",
));
loop {
match tutor.let_user_make_change().run(vec![]).data {
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![]).data().0 {
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),

View File

@ -45,7 +45,7 @@ false
i_name: None,
};
loop {
if let VDataEnum::Bool(true) = tutor.let_user_make_change().run(vec![]).data {
if let VDataEnum::Bool(true) = &tutor.let_user_make_change().run(vec![]).data().0 {
break;
}
}

View File

@ -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,
parse::parse(&mut file).unwrap().run(vec![]).data().0,
VDataEnum::Bool(true)
));
}

View File

@ -57,8 +57,11 @@ fn main() {
.unwrap()
.1;
my_lib.callbacks.run_function.consuming = Some(Box::new(move |msg| {
if let VDataEnum::String(url) = &msg.msg.args[0].data {
let url = url.clone();
let url = if let VDataEnum::String(url) = &msg.msg.args[0].data().0 {
url.clone()
} else {
unreachable!()
};
std::thread::spawn(move || {
let r = match reqwest::blocking::get(url) {
Ok(response) => match response.text() {
@ -89,9 +92,6 @@ fn main() {
};
msg.respond(r)
});
} else {
unreachable!()
}
}));
// because we handle all callbacks, this never returns Err(unhandeled message).
// it returns Ok(()) if mers exits (i/o error in stdin/stdout), so we also exit if that happens.