mirror of
				https://github.com/Dummi26/mers.git
				synced 2025-10-31 19:56:15 +01:00 
			
		
		
		
	changed VData system again, renamed src/script to src/lang and added src/c.mers, which is an example something that currently does not work properly due to the VData implementation (and serves as a reminder to fix the issue)
This commit is contained in:
		
							parent
							
								
									f8102c8fe6
								
							
						
					
					
						commit
						aff55fdc9e
					
				| @ -25,4 +25,3 @@ for word text.regex("\\S+").assume_no_enum() | ||||
|         words = rnd() | ||||
|         sleep(0.75) | ||||
|     } | ||||
| println(" ~ ~ ~ ~ ~ ~ ~ ~ ~ ~") | ||||
|  | ||||
| @ -6,5 +6,10 @@ list = [1 2 3 4 5 6 7 8 9 ...] | ||||
| // second.debug() | ||||
| 
 | ||||
| &list.get_ref(2).assume1() = 24 | ||||
| should_not_be_changeable = &list.get(3).assume1() | ||||
| should_not_be_changeable = 24 | ||||
| 
 | ||||
| if list.get(2) != [24] println("[!!] list.get(2) != 24 (was {0})".format(list.get(2).to_string())) | ||||
| if list.get(3) == [24] println("[!!] list.get(3) == 24") | ||||
| 
 | ||||
| list.debug() | ||||
|  | ||||
| @ -6,7 +6,7 @@ t = thread(() { | ||||
|     println("got words from word list!") | ||||
| }) | ||||
| 
 | ||||
| sleep(0.5) | ||||
| sleep(0.1) | ||||
| 
 | ||||
| // this will finish before the thread does. | ||||
| http_get("https:\//github.com/").assume_no_enum() | ||||
|  | ||||
| @ -1,4 +0,0 @@ | ||||
| a = 1 | ||||
| b = 2 | ||||
| a.debug() | ||||
| b.debug() | ||||
							
								
								
									
										4
									
								
								mers/c.mers
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								mers/c.mers
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| list = [1 ...] | ||||
| b = list | ||||
| &list.pop() | ||||
| list | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -8,15 +8,34 @@ use super::{ | ||||
|     val_type::{VSingleType, VType}, | ||||
| }; | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub enum RStatementEnum { | ||||
|     Value(VData), | ||||
|     Tuple(Vec<RStatement>), | ||||
|     List(Vec<RStatement>), | ||||
|     Variable(Arc<Mutex<VData>>, VType, bool), | ||||
|     FunctionCall(Arc<RFunction>, Vec<RStatement>), | ||||
|     BuiltinFunction(BuiltinFunction, Vec<RStatement>), | ||||
|     LibFunction(usize, usize, Vec<RStatement>, VType), | ||||
|     Block(RBlock), | ||||
|     If(RStatement, RStatement, Option<RStatement>), | ||||
|     Loop(RStatement), | ||||
|     For(Arc<Mutex<VData>>, RStatement, RStatement), | ||||
|     Switch(RStatement, Vec<(VType, RStatement)>), | ||||
|     Match(Arc<Mutex<VData>>, Vec<(RStatement, RStatement)>), | ||||
|     IndexFixed(RStatement, usize), | ||||
|     EnumVariant(usize, RStatement), | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct RBlock { | ||||
|     pub statements: Vec<RStatement>, | ||||
| } | ||||
| impl RBlock { | ||||
|     pub fn run(&self, vars: &mut Vec<VData>, info: &GSInfo) -> VData { | ||||
|     pub fn run(&self, info: &GSInfo) -> VData { | ||||
|         let mut last = None; | ||||
|         for statement in &self.statements { | ||||
|             last = Some(statement.run(vars, info)); | ||||
|             last = Some(statement.run(info)); | ||||
|         } | ||||
|         if let Some(v) = last { | ||||
|             v | ||||
| @ -37,14 +56,14 @@ impl RBlock { | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct RFunction { | ||||
|     pub inputs: Vec<usize>, | ||||
|     pub inputs: Vec<Arc<Mutex<VData>>>, | ||||
|     pub input_types: Vec<VType>, | ||||
|     pub input_output_map: Vec<(Vec<VSingleType>, VType)>, | ||||
|     pub block: RBlock, | ||||
| } | ||||
| impl RFunction { | ||||
|     pub fn run(&self, vars: &mut Vec<VData>, info: &GSInfo) -> VData { | ||||
|         self.block.run(vars, info) | ||||
|     pub fn run(&self, info: &GSInfo) -> VData { | ||||
|         self.block.run(info) | ||||
|     } | ||||
|     pub fn out(&self, input_types: &Vec<VSingleType>) -> VType { | ||||
|         self.input_output_map | ||||
| @ -87,18 +106,25 @@ pub struct RStatement { | ||||
|     pub force_output_type: Option<VType>, | ||||
| } | ||||
| impl RStatement { | ||||
|     pub fn run(&self, vars: &mut Vec<VData>, info: &GSInfo) -> VData { | ||||
|         let out = self.statement.run(vars, info); | ||||
|     pub fn run(&self, info: &GSInfo) -> VData { | ||||
|         let out = self.statement.run(info); | ||||
|         if let Some((v, derefs, is_init)) = &self.output_to { | ||||
|             let mut val = v.run(vars, info); | ||||
|             // even if 0 derefs, deref once because it *has* to end on a reference (otherwise writing to it would be unacceptable as the value might not expect to be modified)
 | ||||
|             for _ in 0..(derefs + 1) { | ||||
|                 val = match val.inner().deref() { | ||||
|                     Some(v) => v, | ||||
|                     None => unreachable!("can't dereference..."), | ||||
|                 }; | ||||
|             'init: { | ||||
|                 if *is_init && *derefs == 0 { | ||||
|                     if let RStatementEnum::Variable(var, _, _) = v.statement.as_ref() { | ||||
|                         *var.lock().unwrap() = out; | ||||
|                         break 'init; | ||||
|                     } | ||||
|                 } | ||||
|                 let mut val = v.run(info); | ||||
|                 for _ in 0..(*derefs + 1) { | ||||
|                     val = match val.deref() { | ||||
|                         Some(v) => v, | ||||
|                         None => unreachable!("can't dereference..."), | ||||
|                     }; | ||||
|                 } | ||||
|                 val.assign(out); | ||||
|             } | ||||
|             val.assign(out.inner()); | ||||
|             VDataEnum::Tuple(vec![]).to() | ||||
|         } else { | ||||
|             out | ||||
| @ -118,32 +144,14 @@ impl RStatement { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub enum RStatementEnum { | ||||
|     Value(VData), | ||||
|     Tuple(Vec<RStatement>), | ||||
|     List(Vec<RStatement>), | ||||
|     Variable(usize, VType, bool), | ||||
|     FunctionCall(Arc<RFunction>, Vec<RStatement>), | ||||
|     BuiltinFunction(BuiltinFunction, Vec<RStatement>), | ||||
|     LibFunction(usize, usize, Vec<RStatement>, VType), | ||||
|     Block(RBlock), | ||||
|     If(RStatement, RStatement, Option<RStatement>), | ||||
|     Loop(RStatement), | ||||
|     For(usize, RStatement, RStatement), | ||||
|     Switch(RStatement, Vec<(VType, RStatement)>), | ||||
|     Match(usize, Vec<(RStatement, RStatement)>), | ||||
|     IndexFixed(RStatement, usize), | ||||
|     EnumVariant(usize, RStatement), | ||||
| } | ||||
| impl RStatementEnum { | ||||
|     pub fn run(&self, vars: &mut Vec<VData>, info: &GSInfo) -> VData { | ||||
|     pub fn run(&self, info: &GSInfo) -> VData { | ||||
|         match self { | ||||
|             Self::Value(v) => v.clone(), | ||||
|             Self::Tuple(v) => { | ||||
|                 let mut w = vec![]; | ||||
|                 for v in v { | ||||
|                     w.push(v.run(vars, info)); | ||||
|                     w.push(v.run(info)); | ||||
|                 } | ||||
|                 VDataEnum::Tuple(w).to() | ||||
|             } | ||||
| @ -151,7 +159,7 @@ impl RStatementEnum { | ||||
|                 let mut w = vec![]; | ||||
|                 let mut out = VType { types: vec![] }; | ||||
|                 for v in v { | ||||
|                     let val = v.run(vars, info); | ||||
|                     let val = v.run(info); | ||||
|                     out = out | val.out(); | ||||
|                     w.push(val); | ||||
|                 } | ||||
| @ -159,30 +167,29 @@ impl RStatementEnum { | ||||
|             } | ||||
|             Self::Variable(v, _, is_ref) => { | ||||
|                 if *is_ref { | ||||
|                     // shared mutability (clone_mut)
 | ||||
|                     VDataEnum::Reference(vars[*v].clone_mut()).to() | ||||
|                     VDataEnum::Reference(v.lock().unwrap().clone_mut()).to() | ||||
|                 } else { | ||||
|                     // Copy on Write (clone)
 | ||||
|                     vars[*v].clone() | ||||
|                     v.lock().unwrap().clone_data() | ||||
|                 } | ||||
|             } | ||||
|             Self::FunctionCall(func, args) => { | ||||
|                 for (i, input) in func.inputs.iter().enumerate() { | ||||
|                     vars[*input] = args[i].run(vars, info); | ||||
|                     input.lock().unwrap().assign(args[i].run(info)); | ||||
|                 } | ||||
|                 func.run(vars, info) | ||||
|                 func.run(info) | ||||
|             } | ||||
|             Self::BuiltinFunction(v, args) => v.run(args, vars, info), | ||||
|             Self::LibFunction(libid, fnid, args, _) => info.libs[*libid] | ||||
|                 .run_fn(*fnid, args.iter().map(|arg| arg.run(vars, info)).collect()), | ||||
|             Self::Block(b) => b.run(vars, info), | ||||
|             Self::If(c, t, e) => { | ||||
|                 if let VDataEnum::Bool(v) = &c.run(vars, info).data().0 { | ||||
|             Self::BuiltinFunction(v, args) => v.run(args, info), | ||||
|             Self::LibFunction(libid, fnid, args, _) => { | ||||
|                 info.libs[*libid].run_fn(*fnid, args.iter().map(|arg| arg.run(info)).collect()) | ||||
|             } | ||||
|             Self::Block(b) => b.run(info), | ||||
|             Self::If(c, t, e) => c.run(info).operate_on_data_immut(|v| { | ||||
|                 if let VDataEnum::Bool(v) = v { | ||||
|                     if *v { | ||||
|                         t.run(vars, info) | ||||
|                         t.run(info) | ||||
|                     } else { | ||||
|                         if let Some(e) = e { | ||||
|                             e.run(vars, info) | ||||
|                             e.run(info) | ||||
|                         } else { | ||||
|                             VDataEnum::Tuple(vec![]).to() | ||||
|                         } | ||||
| @ -190,75 +197,71 @@ impl RStatementEnum { | ||||
|                 } else { | ||||
|                     unreachable!() | ||||
|                 } | ||||
|             } | ||||
|             }), | ||||
|             Self::Loop(c) => loop { | ||||
|                 // loops will break if the value matches.
 | ||||
|                 if let Some(break_val) = c.run(vars, info).inner().matches() { | ||||
|                 if let Some(break_val) = c.run(info).matches() { | ||||
|                     break break_val; | ||||
|                 } | ||||
|             }, | ||||
|             Self::For(v, c, b) => { | ||||
|                 // matching values also break with value from a for loop.
 | ||||
|                 let c = c.run(vars, info); | ||||
|                 let mut vars = vars.clone(); | ||||
|                 let in_loop = |vars: &mut Vec<VData>, c| { | ||||
|                     vars[*v] = c; | ||||
|                     b.run(vars, info) | ||||
|                 }; | ||||
|                 c.run(info).operate_on_data_immut(|c: &VDataEnum| { | ||||
|                     let mut in_loop = |c: VData| { | ||||
|                         *v.lock().unwrap() = c; | ||||
|                         b.run(info) | ||||
|                     }; | ||||
| 
 | ||||
|                 let mut oval = VDataEnum::Tuple(vec![]).to(); | ||||
|                 match &c.data().0 { | ||||
|                     VDataEnum::Int(v) => { | ||||
|                         for i in 0..*v { | ||||
|                             if let Some(v) = | ||||
|                                 in_loop(&mut vars, VDataEnum::Int(i).to()).inner().matches() | ||||
|                             { | ||||
|                                 oval = v; | ||||
|                                 break; | ||||
|                     let mut oval = VDataEnum::Tuple(vec![]).to(); | ||||
|                     match c { | ||||
|                         VDataEnum::Int(v) => { | ||||
|                             for i in 0..*v { | ||||
|                                 if let Some(v) = in_loop(VDataEnum::Int(i).to()).matches() { | ||||
|                                     oval = v; | ||||
|                                     break; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         VDataEnum::String(v) => { | ||||
|                             for ch in v.chars() { | ||||
|                                 if let Some(v) = | ||||
|                                     in_loop(VDataEnum::String(ch.to_string()).to()).matches() | ||||
|                                 { | ||||
|                                     oval = v; | ||||
|                                     break; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         VDataEnum::Tuple(v) | VDataEnum::List(_, v) => { | ||||
|                             for v in v { | ||||
|                                 if let Some(v) = in_loop(v.clone()).matches() { | ||||
|                                     oval = v; | ||||
|                                     break; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         VDataEnum::Function(f) => loop { | ||||
|                             if let Some(v) = f.run(info).matches() { | ||||
|                                 if let Some(v) = in_loop(v).matches() { | ||||
|                                     oval = v; | ||||
|                                     break; | ||||
|                                 } | ||||
|                             } else { | ||||
|                                 break; | ||||
|                             } | ||||
|                         }, | ||||
|                         _ => unreachable!(), | ||||
|                     } | ||||
|                     VDataEnum::String(v) => { | ||||
|                         for ch in v.chars() { | ||||
|                             if let Some(v) = | ||||
|                                 in_loop(&mut vars, VDataEnum::String(ch.to_string()).to()) | ||||
|                                     .inner() | ||||
|                                     .matches() | ||||
|                             { | ||||
|                                 oval = v; | ||||
|                                 break; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     VDataEnum::Tuple(v) | VDataEnum::List(_, v) => { | ||||
|                         for v in v { | ||||
|                             if let Some(v) = in_loop(&mut vars, v.clone()).inner().matches() { | ||||
|                                 oval = v; | ||||
|                                 break; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     VDataEnum::Function(f) => loop { | ||||
|                         if let Some(v) = f.run(&mut vars, info).inner().matches() { | ||||
|                             if let Some(v) = in_loop(&mut vars, v).inner().matches() { | ||||
|                                 oval = v; | ||||
|                                 break; | ||||
|                             } | ||||
|                         } else { | ||||
|                             break; | ||||
|                         } | ||||
|                     }, | ||||
|                     _ => unreachable!(), | ||||
|                 } | ||||
|                 oval | ||||
|                     oval | ||||
|                 }) | ||||
|             } | ||||
|             Self::Switch(switch_on, cases) => { | ||||
|                 let switch_on = switch_on.run(vars, info); | ||||
|                 let switch_on = switch_on.run(info); | ||||
|                 let switch_on_type = switch_on.out(); | ||||
|                 let mut out = VDataEnum::Tuple(vec![]).to(); | ||||
|                 for (case_type, case_action) in cases.iter() { | ||||
|                     if switch_on_type.fits_in(case_type, info).is_empty() { | ||||
|                         out = case_action.run(vars, info); | ||||
|                         out = case_action.run(info); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
| @ -267,17 +270,17 @@ impl RStatementEnum { | ||||
|             Self::Match(match_on, cases) => 'm: { | ||||
|                 for (case_condition, case_action) in cases { | ||||
|                     // [t] => Some(t), t => Some(t), [] | false => None
 | ||||
|                     if let Some(v) = case_condition.run(vars, info).inner().matches() { | ||||
|                         let og = { std::mem::replace(&mut vars[*match_on], v) }; | ||||
|                         let res = case_action.run(vars, info); | ||||
|                         vars[*match_on] = og; | ||||
|                     if let Some(v) = case_condition.run(info).matches() { | ||||
|                         let og = { std::mem::replace(&mut *match_on.lock().unwrap(), v) }; | ||||
|                         let res = case_action.run(info); | ||||
|                         *match_on.lock().unwrap() = og; | ||||
|                         break 'm res; | ||||
|                     } | ||||
|                 } | ||||
|                 VDataEnum::Tuple(vec![]).to() | ||||
|             } | ||||
|             Self::IndexFixed(st, i) => st.run(vars, info).get(*i, false).unwrap(), | ||||
|             Self::EnumVariant(e, v) => VDataEnum::EnumVariant(*e, Box::new(v.run(vars, info))).to(), | ||||
|             Self::IndexFixed(st, i) => st.run(info).get(*i).unwrap(), | ||||
|             Self::EnumVariant(e, v) => VDataEnum::EnumVariant(*e, Box::new(v.run(info))).to(), | ||||
|         } | ||||
|     } | ||||
|     pub fn out(&self, info: &GlobalScriptInfo) -> VType { | ||||
| @ -376,7 +379,7 @@ impl RScript { | ||||
|         Ok(Self { main, info }) | ||||
|     } | ||||
|     pub fn run(&self, args: Vec<String>) -> VData { | ||||
|         let mut vars = Vec::with_capacity(self.info.vars); | ||||
|         let mut vars = vec![]; | ||||
|         vars.push( | ||||
|             VDataEnum::List( | ||||
|                 VSingleType::String.into(), | ||||
| @ -386,10 +389,7 @@ impl RScript { | ||||
|             ) | ||||
|             .to(), | ||||
|         ); | ||||
|         for _i in 1..self.info.vars { | ||||
|             vars.push(VDataEnum::Tuple(vec![]).to()); | ||||
|         } | ||||
|         self.main.run(&mut vars, &self.info) | ||||
|         self.main.run(&self.info) | ||||
|     } | ||||
|     pub fn info(&self) -> &GSInfo { | ||||
|         &self.info | ||||
| @ -8,8 +8,6 @@ pub type GSInfo = Arc<GlobalScriptInfo>; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct GlobalScriptInfo { | ||||
|     pub vars: usize, | ||||
| 
 | ||||
|     pub libs: Vec<libs::Lib>, | ||||
|     pub lib_fns: HashMap<String, (usize, usize)>, | ||||
| 
 | ||||
| @ -28,7 +26,6 @@ impl GlobalScriptInfo { | ||||
| impl Default for GlobalScriptInfo { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             vars: 0, | ||||
|             libs: vec![], | ||||
|             lib_fns: HashMap::new(), | ||||
|             enum_variants: Self::default_enum_variants(), | ||||
							
								
								
									
										0
									
								
								mers/src/script/mod.rs → mers/src/lang/mod.rs
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								mers/src/script/mod.rs → mers/src/lang/mod.rs
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -1,17 +1,17 @@ | ||||
| use std::{ | ||||
|     collections::HashMap, | ||||
|     fmt::{Debug, Display}, | ||||
|     sync::Arc, | ||||
|     sync::{Arc, Mutex}, | ||||
| }; | ||||
| 
 | ||||
| use crate::{ | ||||
|     libs, | ||||
|     script::{ | ||||
|     lang::{ | ||||
|         builtins, | ||||
|         global_info::GlobalScriptInfo, | ||||
|         val_data::VDataEnum, | ||||
|         val_data::{VData, VDataEnum}, | ||||
|         val_type::{VSingleType, VType}, | ||||
|     }, | ||||
|     libs, | ||||
| }; | ||||
| 
 | ||||
| use super::{ | ||||
| @ -158,7 +158,7 @@ impl ToRunnableError { | ||||
| // Local, used to keep local variables separated
 | ||||
| #[derive(Clone)] | ||||
| struct LInfo { | ||||
|     vars: HashMap<String, (usize, VType)>, | ||||
|     vars: HashMap<String, (Arc<Mutex<VData>>, VType)>, | ||||
|     fns: HashMap<String, Arc<RFunction>>, | ||||
| } | ||||
| 
 | ||||
| @ -200,7 +200,7 @@ fn get_all_functions( | ||||
|     s: &SFunction, | ||||
|     ginfo: &mut GlobalScriptInfo, | ||||
|     linfo: &mut LInfo, | ||||
|     input_vars: &Vec<usize>, | ||||
|     input_vars: &Vec<Arc<Mutex<VData>>>, | ||||
|     inputs: &mut Vec<VSingleType>, | ||||
|     out: &mut Vec<(Vec<VSingleType>, VType)>, | ||||
| ) -> Result<(), ToRunnableError> { | ||||
| @ -240,12 +240,12 @@ fn function( | ||||
|     for (iname, itype) in &s.inputs { | ||||
|         let mut itype = itype.to_owned(); | ||||
|         stypes(&mut itype, ginfo)?; | ||||
|         let var = Arc::new(Mutex::new(VData::new_placeholder())); | ||||
|         linfo | ||||
|             .vars | ||||
|             .insert(iname.clone(), (ginfo.vars, itype.clone())); | ||||
|         input_vars.push(ginfo.vars); | ||||
|             .insert(iname.clone(), (Arc::clone(&var), itype.clone())); | ||||
|         input_vars.push(var); | ||||
|         input_types.push(itype); | ||||
|         ginfo.vars += 1; | ||||
|     } | ||||
|     let mut all_outs = vec![]; | ||||
|     get_all_functions( | ||||
| @ -367,13 +367,19 @@ fn statement_adv( | ||||
|                 if !linfo.vars.contains_key(v) { | ||||
|                     if let Some((t, is_init)) = to_be_assigned_to { | ||||
|                         *is_init = true; | ||||
|                         linfo.vars.insert(v.to_owned(), (ginfo.vars, t)); | ||||
|                         ginfo.vars += 1; | ||||
|                         linfo.vars.insert(v.to_owned(), (Arc::new(Mutex::new(VData::new_placeholder())), t)); | ||||
|                     } | ||||
|                 } | ||||
|                 if let Some(var) = linfo.vars.get(v) { | ||||
|                     RStatementEnum::Variable(var.0, { | ||||
|                         let mut v = var.1.clone(); stypes(&mut v, ginfo)?; v }, *is_ref) | ||||
|                     RStatementEnum::Variable( | ||||
|                         Arc::clone(&var.0), | ||||
|                         { | ||||
|                             let mut v = var.1.clone(); | ||||
|                             stypes(&mut v, ginfo)?; | ||||
|                             v | ||||
|                         }, | ||||
|                         *is_ref | ||||
|                     ) | ||||
|                 } else { | ||||
|                         return Err(ToRunnableError::UseOfUndefinedVariable(v.clone())); | ||||
|                 } | ||||
| @ -442,7 +448,7 @@ fn statement_adv( | ||||
|                 } else { | ||||
|                     // anonymous function => return as value
 | ||||
|                     RStatementEnum::Value( | ||||
|                         VDataEnum::Function(function(f, ginfo, linfo.clone())?).to(), | ||||
|                         VDataEnum::Function(Arc::new(function(f, ginfo, linfo.clone())?)).to(), | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
| @ -479,11 +485,10 @@ fn statement_adv( | ||||
|                 if inner.types.is_empty() { | ||||
|                     return Err(ToRunnableError::ForLoopContainerHasNoInnerTypes); | ||||
|                 } | ||||
|                 let for_loop_var = Arc::new(Mutex::new(VData::new_placeholder())); | ||||
|                 linfo | ||||
|                     .vars | ||||
|                     .insert(v.clone(), (ginfo.vars, inner)); | ||||
|                 let for_loop_var = ginfo.vars; | ||||
|                 ginfo.vars += 1; | ||||
|                     .insert(v.clone(), (Arc::clone(&for_loop_var), inner)); | ||||
|                 let block = statement(&b, ginfo, &mut linfo)?; | ||||
|                 let o = RStatementEnum::For(for_loop_var, container, block); | ||||
|                 o | ||||
| @ -1,6 +1,6 @@ | ||||
| use std::{ | ||||
|     fmt::{self, Debug, Display, Formatter}, | ||||
|     sync::{Arc, Mutex}, | ||||
|     sync::{Arc, Mutex, MutexGuard}, | ||||
| }; | ||||
| 
 | ||||
| use super::{ | ||||
| @ -9,122 +9,6 @@ use super::{ | ||||
|     val_type::{VSingleType, VType}, | ||||
| }; | ||||
| 
 | ||||
| pub struct VData { | ||||
|     /// (_, mutable) - if false, behave as CopyOnWrite.
 | ||||
|     pub data: Arc<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; | ||||
|             } | ||||
|         } | ||||
|         // #[cfg(debug_assertions)]
 | ||||
|         // eprintln!("VData: assign: overwriting my previous Arc because it was immutable.");
 | ||||
|         *self = new_val.to(); | ||||
|     } | ||||
|     pub fn inner_replace(&mut self, new_val: VDataEnum) -> VDataEnum { | ||||
|         { | ||||
|             let mut d = self.data.lock().unwrap(); | ||||
|             if d.1 { | ||||
|                 return std::mem::replace(&mut d.0, new_val); | ||||
|             } | ||||
|         } | ||||
|         let o = self.data().0.clone(); | ||||
|         *self = new_val.to(); | ||||
|         o | ||||
|     } | ||||
|     /// returns the contained VDataEnum. May or may not clone.
 | ||||
|     pub fn inner(self) -> VDataEnum { | ||||
|         // Arc::unwrap_or_clone(self.data).lock().unwrap().0
 | ||||
|         let o = match Arc::try_unwrap(self.data) { | ||||
|             Ok(v) => std::mem::replace(&mut v.lock().unwrap().0, VDataEnum::Bool(false)), | ||||
|             Err(e) => e.lock().unwrap().0.clone(), | ||||
|         }; | ||||
|         o | ||||
|     } | ||||
|     /// ensures self is mutable, then returns a new instance of VData that is also mutable and uses the same Arc<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.
 | ||||
|         let o = self.clone_mut_assume(); | ||||
|         o | ||||
|     } | ||||
|     /// like clone_mut, but assumes self is already mutable, and therefor does not need to mutate self
 | ||||
|     /// as the Arc<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(); | ||||
|             if !s.1 { | ||||
|                 if Arc::strong_count(&self.data) > 1 { | ||||
|                     // not mutable yet - clone the value to avoid modifying an immutable one.
 | ||||
|                     #[cfg(debug_assertions)] | ||||
|                     eprintln!("VData: actually copying value due to mutation of an immutable shared value. (strong count: {})", Arc::strong_count(&self.data)); | ||||
|                     *s = (s.0.clone(), true); | ||||
|                 } else { | ||||
|                     // value was immutable, but not shared, so we can just make it mutable.
 | ||||
|                     s.1 = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         self | ||||
|     } | ||||
|     pub fn data(&self) -> std::sync::MutexGuard<(VDataEnum, bool)> { | ||||
|         self.data.lock().unwrap() | ||||
|     } | ||||
| } | ||||
| impl Clone for VData { | ||||
|     fn clone(&self) -> Self { | ||||
|         let mut d = self.data.lock().unwrap(); | ||||
|         let o = if d.1 { | ||||
|             // mutable, copy the value to avoid accidentally modifying it.
 | ||||
|             // DON'T just set it to immutable even if we are the only reference (inner mutability!)
 | ||||
|             #[cfg(debug_assertions)] | ||||
|             eprintln!( | ||||
|                 "VData: Clone: copying value due to clone of a mutable value. (strong count: {})", | ||||
|                 Arc::strong_count(&self.data) | ||||
|             ); | ||||
|             d.0.clone().to() | ||||
|         } else { | ||||
|             // immutable, return the same arc (-> avoid cloning)
 | ||||
|             Self { | ||||
|                 data: Arc::clone(&self.data), | ||||
|             } | ||||
|         }; | ||||
|         o | ||||
|     } | ||||
| } | ||||
| impl Debug for VData { | ||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | ||||
|         let d = self.data.lock().unwrap(); | ||||
|         if d.1 { | ||||
|             write!(f, "(!mutable!):{:?}", d.0) | ||||
|         } else { | ||||
|             write!(f, "(immutable):{:?}", d.0) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| impl PartialEq for VData { | ||||
|     fn eq(&self, other: &Self) -> bool { | ||||
|         self.data().0 == other.data().0 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum VDataEnum { | ||||
|     Bool(bool), | ||||
| @ -133,17 +17,214 @@ pub enum VDataEnum { | ||||
|     String(String), | ||||
|     Tuple(Vec<VData>), | ||||
|     List(VType, Vec<VData>), | ||||
|     Function(RFunction), | ||||
|     Function(Arc<RFunction>), | ||||
|     Thread(thread::VDataThread, VType), | ||||
|     Reference(VData), | ||||
|     EnumVariant(usize, Box<VData>), | ||||
| } | ||||
| 
 | ||||
| pub struct VData(Arc<Mutex<VDataInner>>); | ||||
| enum VDataInner { | ||||
|     Data(usize, Box<VDataEnum>), | ||||
|     Mut(Arc<Mutex<VData>>), | ||||
|     ClonedFrom(VData), | ||||
| } | ||||
| /// can be either Data, Mut or ClonedFrom.
 | ||||
| /// - any ClonedFrom will point to a Data variant. It can never point to anything else.
 | ||||
| ///   it will increase the Data's clone count by one on creation and decrease it again on Drop::drop().
 | ||||
| /// - any Mut will eventually point to a ClonedFrom or a Data variant. It can also point to another Mut.
 | ||||
| impl VDataInner { | ||||
|     fn to(self) -> VData { | ||||
|         VData(Arc::new(Mutex::new(self))) | ||||
|     } | ||||
| } | ||||
| impl VDataEnum { | ||||
|     pub fn to(self) -> VData { | ||||
|         VDataInner::Data(0, Box::new(self)).to() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl VData { | ||||
|     pub fn new_placeholder() -> Self { | ||||
|         VDataEnum::Bool(false).to() | ||||
|     } | ||||
|     /// clones self, retrurning a new instance of self that will always yield the value self had when this function was called.
 | ||||
|     /// note to dev: since the actual data is stored in VDataEnum, which either clones data or calls clone() (= clone_data()) on further VData, this automatically borrows all child data as immutable too. rust's Drop::drop() implementation (probably) handles everything for us too, so this can be implemented without thinking about recursion.
 | ||||
|     pub fn clone_data(&self) -> Self { | ||||
|         match &mut *self.0.lock().unwrap() { | ||||
|             VDataInner::Data(cloned, _data) => { | ||||
|                 *cloned += 1; | ||||
|                 VDataInner::ClonedFrom(self.clone_arc()).to() | ||||
|             } | ||||
|             VDataInner::Mut(inner) => inner.lock().unwrap().clone_data(), | ||||
|             VDataInner::ClonedFrom(inner) => inner.clone_data(), | ||||
|         } | ||||
|     } | ||||
|     /// clones self, returning a new instance of self that will always yield the same data as self, so that changes done to either are shared between both.
 | ||||
|     pub fn clone_mut(&self) -> Self { | ||||
|         VDataInner::Mut(Arc::new(Mutex::new(self.clone_arc()))).to() | ||||
|     } | ||||
|     fn clone_arc(&self) -> Self { | ||||
|         Self(Arc::clone(&self.0)) | ||||
|     } | ||||
|     pub fn operate_on_data_immut<F, O>(&self, mut func: F) -> O | ||||
|     where | ||||
|         F: FnOnce(&VDataEnum) -> O, | ||||
|     { | ||||
|         match &*self.0.lock().unwrap() { | ||||
|             VDataInner::Data(_, data) => func(data.as_ref()), | ||||
|             VDataInner::Mut(inner) => inner.lock().unwrap().operate_on_data_immut(func), | ||||
|             VDataInner::ClonedFrom(inner) => inner.operate_on_data_immut(func), | ||||
|         } | ||||
|     } | ||||
|     /// runs func on the underlying data.
 | ||||
|     /// attempts to get a mutable reference to the data. if this fails, it will (partially) clone the data, then point the VData to the new data,
 | ||||
|     /// so that other VDatas pointing to the same original data aren't changed.
 | ||||
|     pub fn operate_on_data_mut<F, O>(&mut self, mut func: F) -> O | ||||
|     where | ||||
|         F: FnOnce(&mut VDataEnum) -> O, | ||||
|     { | ||||
|         let (new_val, o) = { | ||||
|             match &mut *self.0.lock().unwrap() { | ||||
|                 VDataInner::Data(count, data) => { | ||||
|                     if *count == 0 { | ||||
|                         (None, func(data.as_mut())) | ||||
|                     } else { | ||||
|                         #[cfg(debug_assertions)] | ||||
|                         eprintln!("Cloning: data should be modified, but was borrowed immutably."); | ||||
|                         let mut new_data = data.clone(); | ||||
|                         let o = func(new_data.as_mut()); | ||||
|                         // *self doesn't modify the ::Data, it instead points the value that wraps it to a new ::Data, leaving the old one as it was.
 | ||||
|                         // for proof: data is untouched, only the new_data is ever modified.
 | ||||
|                         (Some(VDataInner::Data(0, new_data).to()), o) | ||||
|                     } | ||||
|                 } | ||||
|                 VDataInner::Mut(inner) => (None, inner.lock().unwrap().operate_on_data_mut(func)), | ||||
|                 VDataInner::ClonedFrom(inner) => (None, inner.operate_on_data_mut(func)), | ||||
|             } | ||||
|         }; | ||||
|         if let Some(nv) = new_val { | ||||
|             *self = nv; | ||||
|         } | ||||
|         o | ||||
|     } | ||||
| 
 | ||||
|     /// Since operate_on_data_mut can clone, it may be inefficient for just assigning (where we don't care about the previous value, so it doesn't need to be cloned).
 | ||||
|     /// This is what this function is for. (TODO: actually make it more efficient instead of using operate_on_data_mut)
 | ||||
|     pub fn assign_data(&mut self, new_data: VDataEnum) { | ||||
|         self.operate_on_data_mut(|d| *d = new_data) | ||||
|     } | ||||
|     /// Assigns the new_data to self. Affects all muts pointing to the same data, but no ClonedFroms.
 | ||||
|     pub fn assign(&mut self, new: VData) { | ||||
|         self.assign_data(new.inner_cloned()) | ||||
|         // !PROBLEM! If ClonedFrom always has to point to a Data, this may break things!
 | ||||
|         // match &mut *self.0.lock().unwrap() {
 | ||||
|         //     VDataInner::Data(count, data) => {
 | ||||
|         //         // *self doesn't modify the ::Data, it instead points the value that wraps it to a new ::Data, leaving the old one as it was.
 | ||||
|         //         // for proof: data is untouched.
 | ||||
|         //         *self = new_data;
 | ||||
|         //     }
 | ||||
|         //     VDataInner::Mut(inner) => inner.lock().unwrap().assign(new_data),
 | ||||
|         //     VDataInner::ClonedFrom(inner) => inner.assign(new_data),
 | ||||
|         // }
 | ||||
|     } | ||||
| } | ||||
| impl Drop for VDataInner { | ||||
|     fn drop(&mut self) { | ||||
|         if let Self::ClonedFrom(origin) = self { | ||||
|             if let Self::Data(ref_count, _data) = &mut *origin.0.lock().unwrap() { | ||||
|                 eprint!("rc: {}", *ref_count); | ||||
|                 *ref_count = ref_count.saturating_sub(1); | ||||
|                 eprintln!(" -> {}", *ref_count); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl VData { | ||||
|     /// this will always clone! if a reference or mutable reference is enough, use operate_on_data_* instead!
 | ||||
|     pub fn inner_cloned(&self) -> VDataEnum { | ||||
|         self.operate_on_data_immut(|v| v.clone()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // - - make VData act like VDataEnum (as if it were real data) - -
 | ||||
| 
 | ||||
| impl Clone for VData { | ||||
|     fn clone(&self) -> Self { | ||||
|         self.clone_data() | ||||
|     } | ||||
| } | ||||
| impl VData { | ||||
|     pub fn fmtgs(&self, f: &mut Formatter<'_>, info: Option<&GlobalScriptInfo>) -> fmt::Result { | ||||
|         self.operate_on_data_immut(|v| v.fmtgs(f, info)) | ||||
|     } | ||||
| } | ||||
| impl Debug for VData { | ||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | ||||
|         self.operate_on_data_immut(|v| Debug::fmt(v, f)) | ||||
|     } | ||||
| } | ||||
| impl Display for VData { | ||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | ||||
|         self.operate_on_data_immut(|v| Display::fmt(v, f)) | ||||
|     } | ||||
| } | ||||
| impl PartialEq for VData { | ||||
|     fn eq(&self, other: &Self) -> bool { | ||||
|         self.operate_on_data_immut(|a| other.operate_on_data_immut(|b| a == b)) | ||||
|     } | ||||
| } | ||||
| impl PartialEq<VDataEnum> for VData { | ||||
|     fn eq(&self, other: &VDataEnum) -> bool { | ||||
|         self.operate_on_data_immut(|a| a == other) | ||||
|     } | ||||
| } | ||||
| impl PartialEq<VData> for VDataEnum { | ||||
|     fn eq(&self, other: &VData) -> bool { | ||||
|         other.operate_on_data_immut(|b| self == b) | ||||
|     } | ||||
| } | ||||
| impl VData { | ||||
|     pub fn out_single(&self) -> VSingleType { | ||||
|         self.operate_on_data_immut(|v| v.out_single()) | ||||
|     } | ||||
|     pub fn out(&self) -> VType { | ||||
|         self.out_single().to() | ||||
|     } | ||||
|     pub fn noenum(&self) -> Self { | ||||
|         if let Some(v) = self.operate_on_data_immut(|v| v.noenum()) { | ||||
|             v | ||||
|         } else { | ||||
|             self.clone_data() | ||||
|         } | ||||
|     } | ||||
|     pub fn safe_to_share(&self) -> bool { | ||||
|         self.operate_on_data_immut(|v| v.safe_to_share()) | ||||
|     } | ||||
|     pub fn get(&self, i: usize) -> Option<VData> { | ||||
|         self.operate_on_data_immut(|v| v.get(i)) | ||||
|     } | ||||
|     pub fn matches(&self) -> Option<Self> { | ||||
|         match self.operate_on_data_immut(|v| v.matches()) { | ||||
|             Some(Some(v)) => Some(v), | ||||
|             Some(None) => Some(self.clone_data()), | ||||
|             None => None, | ||||
|         } | ||||
|     } | ||||
|     pub fn deref(&self) -> Option<Self> { | ||||
|         self.operate_on_data_immut(|v| v.deref()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // - - VDataEnum - -
 | ||||
| 
 | ||||
| impl Clone for VDataEnum { | ||||
|     fn clone(&self) -> Self { | ||||
|         match self { | ||||
|             // exception: don't clone the value AND don't use CoW,
 | ||||
|             // because we want to share the same Arc<Mutex<_>>.
 | ||||
|             Self::Reference(r) => Self::Reference(r.clone_mut_assume()), | ||||
|             Self::Reference(r) => Self::Reference(r.clone_mut()), | ||||
|             // default impls
 | ||||
|             Self::Bool(b) => Self::Bool(*b), | ||||
|             Self::Int(i) => Self::Int(*i), | ||||
| @ -161,8 +242,8 @@ impl PartialEq for VDataEnum { | ||||
|     fn eq(&self, other: &Self) -> bool { | ||||
|         match (self, other) { | ||||
|             (Self::Reference(a), Self::Reference(b)) => a == b, | ||||
|             (Self::Reference(a), b) => &a.data().0 == b, | ||||
|             (a, Self::Reference(b)) => a == &b.data().0, | ||||
|             (Self::Reference(a), b) => a == b, | ||||
|             (a, Self::Reference(b)) => a == b, | ||||
|             (Self::Bool(a), Self::Bool(b)) => *a == *b, | ||||
|             (Self::Int(a), Self::Int(b)) => *a == *b, | ||||
|             (Self::Float(a), Self::Float(b)) => *a == *b, | ||||
| @ -176,55 +257,26 @@ impl PartialEq for VDataEnum { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl VData { | ||||
|     pub fn safe_to_share(&self) -> bool { | ||||
|         self.data().0.safe_to_share() | ||||
|     } | ||||
|     pub fn out(&self) -> VType { | ||||
|         VType { | ||||
|             types: vec![self.out_single()], | ||||
| impl VDataEnum { | ||||
|     pub fn deref(&self) -> Option<VData> { | ||||
|         if let Self::Reference(r) = self { | ||||
|             Some(r.clone_mut()) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
|     pub fn out_single(&self) -> VSingleType { | ||||
|         match &self.data().0 { | ||||
|             VDataEnum::Bool(..) => VSingleType::Bool, | ||||
|             VDataEnum::Int(..) => VSingleType::Int, | ||||
|             VDataEnum::Float(..) => VSingleType::Float, | ||||
|             VDataEnum::String(..) => VSingleType::String, | ||||
|             VDataEnum::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out()).collect()), | ||||
|             VDataEnum::List(t, _) => VSingleType::List(t.clone()), | ||||
|             VDataEnum::Function(f) => VSingleType::Function(f.input_output_map.clone()), | ||||
|             VDataEnum::Thread(_, o) => VSingleType::Thread(o.clone()), | ||||
|             VDataEnum::Reference(r) => VSingleType::Reference(Box::new(r.out_single())), | ||||
|             VDataEnum::EnumVariant(e, v) => VSingleType::EnumVariant(*e, v.out()), | ||||
|         } | ||||
|     } | ||||
|     pub fn get(&self, i: usize, as_mut: bool) -> Option<Self> { | ||||
|         if let Some(mut d) = self.data().0.get(i) { | ||||
|             if as_mut { | ||||
|                 d.make_mut(); | ||||
|             } | ||||
|             Some(d) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
|     pub fn noenum(self) -> Self { | ||||
|         self.inner().noenum() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl VDataEnum { | ||||
|     pub fn to(self) -> VData { | ||||
|         VData { | ||||
|             data: Arc::new(Mutex::new((self, false))), | ||||
|         } | ||||
|     } | ||||
|     pub fn deref(self) -> Option<VData> { | ||||
|         if let Self::Reference(r) = self { | ||||
|             Some(r) | ||||
|         } else { | ||||
|             None | ||||
|         match self { | ||||
|             Self::Bool(..) => VSingleType::Bool, | ||||
|             Self::Int(..) => VSingleType::Int, | ||||
|             Self::Float(..) => VSingleType::Float, | ||||
|             Self::String(..) => VSingleType::String, | ||||
|             Self::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out_single().to()).collect()), | ||||
|             Self::List(t, _) => VSingleType::List(t.clone()), | ||||
|             Self::Function(f) => VSingleType::Function(f.input_output_map.clone()), | ||||
|             Self::Thread(_, o) => VSingleType::Thread(o.clone()), | ||||
|             Self::Reference(r) => VSingleType::Reference(Box::new(r.out_single())), | ||||
|             Self::EnumVariant(e, v) => VSingleType::EnumVariant(*e, v.out_single().to()), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -240,10 +292,10 @@ impl VDataEnum { | ||||
|             Self::Thread(..) | Self::Reference(..) | Self::EnumVariant(..) => false, | ||||
|         } | ||||
|     } | ||||
|     pub fn noenum(self) -> VData { | ||||
|     pub fn noenum(&self) -> Option<VData> { | ||||
|         match self { | ||||
|             Self::EnumVariant(_, v) => *v, | ||||
|             v => v.to(), | ||||
|             Self::EnumVariant(_, v) => Some(v.clone_data()), | ||||
|             v => None, | ||||
|         } | ||||
|     } | ||||
|     pub fn get(&self, i: usize) -> Option<VData> { | ||||
| @ -259,8 +311,8 @@ impl VDataEnum { | ||||
|                 None => None, | ||||
|             }, | ||||
|             Self::Tuple(v) | Self::List(_, v) => v.get(i).cloned(), | ||||
|             Self::Reference(r) => r.get(i, false), | ||||
|             Self::EnumVariant(_, v) => v.get(i, false), | ||||
|             Self::Reference(r) => r.get(i), | ||||
|             Self::EnumVariant(_, v) => v.get(i), | ||||
|         } | ||||
|     } | ||||
|     pub fn matches_ref_bool(&self) -> bool { | ||||
| @ -270,18 +322,19 @@ impl VDataEnum { | ||||
|             _ => true, | ||||
|         } | ||||
|     } | ||||
|     pub fn matches(self) -> Option<VData> { | ||||
|     /// Some(None) => matches with self
 | ||||
|     pub fn matches(&self) -> Option<Option<VData>> { | ||||
|         match self { | ||||
|             VDataEnum::Tuple(mut tuple) => tuple.pop(), | ||||
|             VDataEnum::Tuple(tuple) => tuple.get(0).cloned().map(|v| Some(v)), | ||||
|             VDataEnum::Bool(v) => { | ||||
|                 if v { | ||||
|                     Some(VDataEnum::Bool(v).to()) | ||||
|                 if *v { | ||||
|                     Some(Some(VDataEnum::Bool(true).to())) | ||||
|                 } else { | ||||
|                     None | ||||
|                 } | ||||
|             } | ||||
|             VDataEnum::EnumVariant(..) => None, | ||||
|             other => Some(other.to()), | ||||
|             other => Some(None), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -460,14 +513,3 @@ impl Display for VDataEnum { | ||||
|         self.fmtgs(f, None) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl VData { | ||||
|     pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result { | ||||
|         self.data().0.fmtgs(f, info) | ||||
|     } | ||||
| } | ||||
| impl Display for VData { | ||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | ||||
|         self.fmtgs(f, None) | ||||
|     } | ||||
| } | ||||
| @ -1,20 +1,20 @@ | ||||
| #![allow(unused)] | ||||
| #![allow(dead_code)] | ||||
| 
 | ||||
| mod lang; | ||||
| mod libs; | ||||
| mod parsing; | ||||
| mod script; | ||||
| 
 | ||||
| pub use lang::{val_data::*, val_type::*}; | ||||
| pub use libs::{ | ||||
|     comms::{ByteData, ByteDataA, Message, RespondableMessage}, | ||||
|     inlib::MyLib, | ||||
| }; | ||||
| pub use parsing::*; | ||||
| pub use script::{val_data::*, val_type::*}; | ||||
| 
 | ||||
| pub mod prelude { | ||||
|     pub use super::{ | ||||
|         script::{val_data::*, val_type::*}, | ||||
|         lang::{val_data::*, val_type::*}, | ||||
|         MyLib, RespondableMessage, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::script::{ | ||||
| use crate::lang::{ | ||||
|     val_data::{VData, VDataEnum}, | ||||
|     val_type::{VSingleType, VType}, | ||||
| }; | ||||
| @ -58,7 +58,7 @@ impl From<run_function::Message> for Message { | ||||
| // implementations for the message/response pairs
 | ||||
| 
 | ||||
| pub mod run_function { | ||||
|     use crate::script::val_data::VData; | ||||
|     use crate::lang::val_data::VData; | ||||
| 
 | ||||
|     use super::{ByteData, ByteDataA, MessageResponse, RespondableMessage}; | ||||
| 
 | ||||
| @ -461,7 +461,7 @@ impl ByteData for VSingleType { | ||||
| } | ||||
| impl ByteDataA for VData { | ||||
|     fn as_byte_data(&self, vec: &mut Vec<u8>) { | ||||
|         self.data().0.as_byte_data(vec) | ||||
|         self.operate_on_data_immut(|v| v.as_byte_data(vec)) | ||||
|     } | ||||
| } | ||||
| impl ByteData for VData { | ||||
|  | ||||
| @ -3,7 +3,7 @@ use std::{ | ||||
|     io::{BufRead, Stdin, StdinLock, Stdout, StdoutLock, Write}, | ||||
| }; | ||||
| 
 | ||||
| use crate::script::{val_data::VData, val_type::VType}; | ||||
| use crate::lang::{val_data::VData, val_type::VType}; | ||||
| 
 | ||||
| use super::{ | ||||
|     comms::{self, ByteData, ByteDataA, Message, MessageResponse, RespondableMessage}, | ||||
|  | ||||
| @ -11,13 +11,13 @@ use std::{ | ||||
| }; | ||||
| 
 | ||||
| use crate::{ | ||||
|     libs::comms::{ByteData, ByteDataA}, | ||||
|     parsing::{file::File, parse}, | ||||
|     script::{ | ||||
|     lang::{ | ||||
|         global_info::GlobalScriptInfo, | ||||
|         val_data::{VData, VDataEnum}, | ||||
|         val_type::VType, | ||||
|     }, | ||||
|     libs::comms::{ByteData, ByteDataA}, | ||||
|     parsing::{file::File, parse}, | ||||
| }; | ||||
| 
 | ||||
| use self::comms::{MessageResponse, RespondableMessage}; | ||||
| @ -93,9 +93,9 @@ impl Lib { | ||||
|             for (_name, func) in registered_fns.iter_mut() { | ||||
|                 for (args, out) in func.iter_mut() { | ||||
|                     for t in args.iter_mut() { | ||||
|                         crate::script::to_runnable::stypes(t, &mut ginfo); | ||||
|                         crate::lang::to_runnable::stypes(t, &mut ginfo); | ||||
|                     } | ||||
|                     crate::script::to_runnable::stypes(out, &mut ginfo); | ||||
|                     crate::lang::to_runnable::stypes(out, &mut ginfo); | ||||
|                 } | ||||
|             } | ||||
|             for (name, id) in ginfo.enum_variants { | ||||
|  | ||||
| @ -6,11 +6,11 @@ use std::{fs, time::Instant}; | ||||
| use notify::Watcher as FsWatcher; | ||||
| 
 | ||||
| mod interactive_mode; | ||||
| mod lang; | ||||
| mod libs; | ||||
| #[cfg(feature = "nushell_plugin")] | ||||
| mod nushell_plugin; | ||||
| mod parsing; | ||||
| mod script; | ||||
| mod tutor; | ||||
| 
 | ||||
| fn main() { | ||||
|  | ||||
| @ -4,11 +4,11 @@ use nu_plugin::{serve_plugin, MsgPackSerializer, Plugin}; | ||||
| use nu_protocol::{PluginExample, PluginSignature, ShellError, Span, Spanned, SyntaxShape, Value}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     parsing, | ||||
|     script::{ | ||||
|     lang::{ | ||||
|         global_info::GlobalScriptInfo, | ||||
|         val_data::{VData, VDataEnum}, | ||||
|     }, | ||||
|     parsing, | ||||
| }; | ||||
| 
 | ||||
| pub fn main() { | ||||
|  | ||||
| @ -1,8 +1,7 @@ | ||||
| use std::{fmt::Debug, process::Command, sync::Arc}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     libs, | ||||
|     script::{ | ||||
|     lang::{ | ||||
|         code_macro::MacroError, | ||||
|         code_parsed::*, | ||||
|         code_runnable::RScript, | ||||
| @ -11,6 +10,7 @@ use crate::{ | ||||
|         val_data::VDataEnum, | ||||
|         val_type::{VSingleType, VType}, | ||||
|     }, | ||||
|     libs, | ||||
| }; | ||||
| 
 | ||||
| use super::file::File; | ||||
| @ -785,7 +785,7 @@ pub mod implementation { | ||||
|                             } | ||||
|                             "!" => { | ||||
|                                 break SStatementEnum::Macro( | ||||
|                                     match crate::script::code_macro::parse_macro(file) { | ||||
|                                     match crate::lang::code_macro::parse_macro(file) { | ||||
|                                         Ok(v) => v, | ||||
|                                         Err(e) => { | ||||
|                                             return Err(ParseError { | ||||
| @ -862,11 +862,17 @@ pub mod implementation { | ||||
|                             let args = [out].into_iter().chain(args.into_iter()).collect(); | ||||
|                             SStatementEnum::FunctionCall(func, args).to() | ||||
|                         } | ||||
|                         SStatementEnum::Value(vd) => match &vd.data().0 { | ||||
|                             VDataEnum::Int(i) => SStatementEnum::IndexFixed(out, *i as _).to(), | ||||
|                             _ => { | ||||
|                         SStatementEnum::Value(vd) => { | ||||
|                             if let Some(i) = vd.operate_on_data_immut(|v| match v { | ||||
|                                 VDataEnum::Int(i) => Some(*i as _), | ||||
|                                 _ => None, | ||||
|                             }) { | ||||
|                                 SStatementEnum::IndexFixed(out, i).to() | ||||
|                             } else { | ||||
|                                 return Err(ParseError { | ||||
|                                     err: ParseErrors::CannotUseFixedIndexingWithThisType(vd.out()), | ||||
|                                     err: ParseErrors::CannotUseFixedIndexingWithThisType( | ||||
|                                         vd.out_single().to(), | ||||
|                                     ), | ||||
|                                     location: err_start_of_wrapper, | ||||
|                                     location_end: Some(err_end_of_wrapper), | ||||
|                                     context: vec![( | ||||
| @ -876,7 +882,7 @@ pub mod implementation { | ||||
|                                     info: None, | ||||
|                                 }); | ||||
|                             } | ||||
|                         }, | ||||
|                         } | ||||
|                         other => { | ||||
|                             return Err(ParseError { | ||||
|                                 err: ParseErrors::CannotWrapWithThisStatement(other), | ||||
| @ -974,6 +980,20 @@ pub mod implementation { | ||||
|                     ) | ||||
|                     .to() | ||||
|                 } | ||||
|                 (0..=50, Some('!')) | ||||
|                     if matches!( | ||||
|                         file.get_char(file.get_pos().current_char_index + 1), | ||||
|                         Some('=') | ||||
|                     ) => | ||||
|                 { | ||||
|                     file.next(); | ||||
|                     file.next(); | ||||
|                     SStatementEnum::FunctionCall( | ||||
|                         "ne".to_owned(), | ||||
|                         vec![out, parse_statement_adv(file, true, 50)?], | ||||
|                     ) | ||||
|                     .to() | ||||
|                 } | ||||
|                 (0..=10, Some('=')) => { | ||||
|                     file.next(); | ||||
|                     match out.statement.as_mut() { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::script::val_data::VDataEnum; | ||||
| use crate::lang::val_data::VDataEnum; | ||||
| 
 | ||||
| use super::Tutor; | ||||
| 
 | ||||
| @ -14,7 +14,7 @@ pub fn run(tutor: &mut Tutor) { | ||||
| ",
 | ||||
|     )); | ||||
|     loop { | ||||
|         match &tutor.let_user_make_change().run(vec![]).data().0 { | ||||
|         match tutor.let_user_make_change().run(vec![]).inner_cloned() { | ||||
|             VDataEnum::Bool(true) => break, | ||||
|             other => { | ||||
|                 tutor.set_status(format!(" - Returned {} instead of true.", other)); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::script::val_data::VDataEnum; | ||||
| use crate::lang::val_data::VDataEnum; | ||||
| 
 | ||||
| use super::Tutor; | ||||
| 
 | ||||
| @ -35,7 +35,7 @@ mul() | ||||
| ",
 | ||||
|     )); | ||||
|     loop { | ||||
|         match &tutor.let_user_make_change().run(vec![]).data().0 { | ||||
|         match tutor.let_user_make_change().run(vec![]).inner_cloned() { | ||||
|             VDataEnum::Int(160) => break, | ||||
|             other => { | ||||
|                 tutor.set_status(format!(" - Returned {other} instead of 160")); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::script::val_data::VDataEnum; | ||||
| use crate::lang::val_data::VDataEnum; | ||||
| 
 | ||||
| use super::Tutor; | ||||
| 
 | ||||
| @ -27,7 +27,7 @@ fn compute_sum(a int b int) { | ||||
| ",
 | ||||
|     )); | ||||
|     loop { | ||||
|         match &tutor.let_user_make_change().run(vec![]).data().0 { | ||||
|         match tutor.let_user_make_change().run(vec![]).inner_cloned() { | ||||
|             VDataEnum::Int(15) => break, | ||||
|             other => { | ||||
|                 tutor.set_status(format!(" - Returned {} instead of 15.", other)); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::script::val_data::VDataEnum; | ||||
| use crate::lang::val_data::VDataEnum; | ||||
| 
 | ||||
| use super::Tutor; | ||||
| 
 | ||||
| @ -54,7 +54,7 @@ switch! words_in_string {} | ||||
| true | ||||
| "));
 | ||||
|     loop { | ||||
|         match &tutor.let_user_make_change().run(vec![]).data().0 { | ||||
|         match tutor.let_user_make_change().run(vec![]).inner_cloned() { | ||||
|             VDataEnum::Tuple(v) if v.is_empty() => { | ||||
|                 tutor.set_status(format!(" - Returned an empty tuple.")); | ||||
|                 tutor.update(None); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::script::val_data::VDataEnum; | ||||
| use crate::lang::val_data::VDataEnum; | ||||
| 
 | ||||
| use super::Tutor; | ||||
| 
 | ||||
| @ -24,7 +24,7 @@ pub fn run(tutor: &mut Tutor) { | ||||
| // return any enum to return to the menu.
 | ||||
| "));
 | ||||
|     loop { | ||||
|         match &tutor.let_user_make_change().run(vec![]).data().0 { | ||||
|         match tutor.let_user_make_change().run(vec![]).inner_cloned() { | ||||
|             VDataEnum::EnumVariant(..) => break, | ||||
|             other => { | ||||
|                 tutor.set_status(format!(" - Returned {other} instead of an enum.")); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::script::val_data::VDataEnum; | ||||
| use crate::lang::val_data::VDataEnum; | ||||
| 
 | ||||
| use super::Tutor; | ||||
| 
 | ||||
| @ -18,7 +18,7 @@ five_less = sub(my_first_variable 5) // 10 | ||||
| ",
 | ||||
|     )); | ||||
|     loop { | ||||
|         match &tutor.let_user_make_change().run(vec![]).data().0 { | ||||
|         match tutor.let_user_make_change().run(vec![]).inner_cloned() { | ||||
|             VDataEnum::String(name) if !name.is_empty() => { | ||||
|                 tutor.i_name = Some(name.to_owned()); | ||||
|                 break; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::script::val_data::VDataEnum; | ||||
| use crate::lang::val_data::VDataEnum; | ||||
| 
 | ||||
| use super::Tutor; | ||||
| 
 | ||||
| @ -44,7 +44,7 @@ switch! first { | ||||
| list.get(8) | ||||
| "));
 | ||||
|     loop { | ||||
|         match &tutor.let_user_make_change().run(vec![]).data().0 { | ||||
|         match tutor.let_user_make_change().run(vec![]).inner_cloned() { | ||||
|             VDataEnum::Tuple(v) if !v.is_empty() => { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::script::val_data::VDataEnum; | ||||
| use crate::lang::val_data::VDataEnum; | ||||
| 
 | ||||
| use super::Tutor; | ||||
| 
 | ||||
| @ -24,9 +24,9 @@ go_to() | ||||
| ",
 | ||||
|         )); | ||||
|         loop { | ||||
|             match &tutor.let_user_make_change().run(vec![]).data().0 { | ||||
|                 VDataEnum::Int(pos) if *pos != 0 => { | ||||
|                     tutor.current_pos = ((*pos).max(0) as usize).min(MAX_POS); | ||||
|             match tutor.let_user_make_change().run(vec![]).inner_cloned() { | ||||
|                 VDataEnum::Int(pos) if pos != 0 => { | ||||
|                     tutor.current_pos = (pos.max(0) as usize).min(MAX_POS); | ||||
|                     match tutor.current_pos { | ||||
|                         0 => continue, | ||||
|                         1 => super::base_comments::run(&mut tutor), | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| use std::{path::PathBuf, thread::JoinHandle, time::Instant}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     lang::{code_runnable::RScript, global_info::GSInfo, val_data::VDataEnum}, | ||||
|     parsing::{self, file::File, parse::ScriptError}, | ||||
|     script::{code_runnable::RScript, global_info::GSInfo, val_data::VDataEnum}, | ||||
| }; | ||||
| 
 | ||||
| mod base_comments; | ||||
| @ -45,7 +45,7 @@ false | ||||
|         i_name: None, | ||||
|     }; | ||||
|     loop { | ||||
|         if let VDataEnum::Bool(true) = &tutor.let_user_make_change().run(vec![]).data().0 { | ||||
|         if let VDataEnum::Bool(true) = tutor.let_user_make_change().run(vec![]).inner_cloned() { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -15,7 +15,7 @@ fn run_all() { | ||||
|                 let mut file = File::new(fs::read_to_string(file.path()).unwrap(), file.path()); | ||||
|                 // has to return true, otherwise the test will fail
 | ||||
|                 assert!(matches!( | ||||
|                     parse::parse(&mut file).unwrap().run(vec![]).data().0, | ||||
|                     parse::parse(&mut file).unwrap().run(vec![]).inner_cloned(), | ||||
|                     VDataEnum::Bool(true) | ||||
|                 )); | ||||
|             } | ||||
|  | ||||
| @ -57,8 +57,8 @@ fn main() { | ||||
|         .unwrap() | ||||
|         .1; | ||||
|     my_lib.callbacks.run_function.consuming = Some(Box::new(move |msg| { | ||||
|         let url = if let VDataEnum::String(url) = &msg.msg.args[0].data().0 { | ||||
|             url.clone() | ||||
|         let url = if let VDataEnum::String(url) = msg.msg.args[0].inner_cloned() { | ||||
|             url | ||||
|         } else { | ||||
|             unreachable!() | ||||
|         }; | ||||
|  | ||||
| @ -1,8 +0,0 @@ | ||||
| &a = "value" | ||||
| &list = ["a" "b" "c" ...] | ||||
| &elem = &list.get_ref(1) | ||||
| switch! elem { | ||||
|     [&string] elem.0 = "z" | ||||
|     [] {} | ||||
| } | ||||
| list.debug() | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 mark
						mark