mirror of
				https://github.com/Dummi26/mers.git
				synced 2025-10-31 11:46:15 +01:00 
			
		
		
		
	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:
		
							parent
							
								
									ceddb886a9
								
							
						
					
					
						commit
						4efee9e2a2
					
				
							
								
								
									
										8
									
								
								get_ref.mers
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								get_ref.mers
									
									
									
									
									
										Normal 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() | ||||
| @ -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 { | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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) => { | ||||
|                     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 | ||||
|             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 { | ||||
|                             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() | ||||
|                         } | ||||
|                     ), | ||||
|                     d => d.to(), | ||||
|                         ) | ||||
|                     } | ||||
|                     _ => { | ||||
|                         drop(a0d); | ||||
|                         a0 | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             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), | ||||
|                                 _ => unreachable!(), | ||||
|                             } | ||||
|                         } | ||||
|                         (VDataEnum::Reference(a), VDataEnum::String(b)) => { | ||||
|                             match &a.lock().unwrap().data { | ||||
|                                 VDataEnum::String(a) => find(a, &b), | ||||
|                                 _ => unreachable!(), | ||||
|                             } | ||||
|                         } | ||||
|                     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.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 { | ||||
|  | ||||
| @ -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") | ||||
|                     } | ||||
|                 } else { | ||||
|                     unreachable!("dereferencing something that isn't a reference in assignment") | ||||
|                 }; | ||||
|                 val = v; | ||||
|                     d.clone_mut() | ||||
|                 } | ||||
|             } | ||||
|             *val.lock().unwrap() = out; | ||||
|             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( | ||||
|             VSingleType::String.into(), | ||||
|             args.into_iter() | ||||
|                 .map(|v| VDataEnum::String(v).to()) | ||||
|                 .collect(), | ||||
|         ) | ||||
|         .to())); | ||||
|         vars.push( | ||||
|             VDataEnum::List( | ||||
|                 VSingleType::String.into(), | ||||
|                 args.into_iter() | ||||
|                     .map(|v| VDataEnum::String(v).to()) | ||||
|                     .collect(), | ||||
|             ) | ||||
|             .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 | ||||
|  | ||||
| @ -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(()) | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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)); | ||||
|  | ||||
| @ -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")); | ||||
|  | ||||
| @ -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)); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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.")); | ||||
|  | ||||
| @ -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(_) => { | ||||
|  | ||||
| @ -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; | ||||
|             } | ||||
|  | ||||
| @ -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), | ||||
|  | ||||
| @ -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; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -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) | ||||
|                 )); | ||||
|             } | ||||
|  | ||||
| @ -57,41 +57,41 @@ 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(); | ||||
|             std::thread::spawn(move || { | ||||
|                 let r = match reqwest::blocking::get(url) { | ||||
|                     Ok(response) => match response.text() { | ||||
|                         Ok(text) => VDataEnum::String(text).to(), | ||||
|                         Err(e) => VDataEnum::EnumVariant( | ||||
|                             err_general, | ||||
|                             Box::new( | ||||
|                                 VDataEnum::EnumVariant( | ||||
|                                     err_getting_response_text, | ||||
|                                     Box::new(VDataEnum::String(e.to_string()).to()), | ||||
|                                 ) | ||||
|                                 .to(), | ||||
|                             ), | ||||
|                         ) | ||||
|                         .to(), | ||||
|                     }, | ||||
|         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() { | ||||
|                     Ok(text) => VDataEnum::String(text).to(), | ||||
|                     Err(e) => VDataEnum::EnumVariant( | ||||
|                         err_general, | ||||
|                         Box::new( | ||||
|                             VDataEnum::EnumVariant( | ||||
|                                 err_building_request, | ||||
|                                 err_getting_response_text, | ||||
|                                 Box::new(VDataEnum::String(e.to_string()).to()), | ||||
|                             ) | ||||
|                             .to(), | ||||
|                         ), | ||||
|                     ) | ||||
|                     .to(), | ||||
|                 }; | ||||
|                 msg.respond(r) | ||||
|             }); | ||||
|         } else { | ||||
|             unreachable!() | ||||
|         } | ||||
|                 }, | ||||
|                 Err(e) => VDataEnum::EnumVariant( | ||||
|                     err_general, | ||||
|                     Box::new( | ||||
|                         VDataEnum::EnumVariant( | ||||
|                             err_building_request, | ||||
|                             Box::new(VDataEnum::String(e.to_string()).to()), | ||||
|                         ) | ||||
|                         .to(), | ||||
|                     ), | ||||
|                 ) | ||||
|                 .to(), | ||||
|             }; | ||||
|             msg.respond(r) | ||||
|         }); | ||||
|     })); | ||||
|     // 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.
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 mark
						mark