From 260e42d4a7a76ca133271868052ec975e2306b39 Mon Sep 17 00:00:00 2001 From: Dummi26 Date: Thu, 30 Mar 2023 19:11:21 +0200 Subject: [PATCH] changed while loop break to use matching (any matching value breaks) and added the same break functionality to for loops. --- src/script/block.rs | 69 ++++++++++++++---------------------------- src/script/val_data.rs | 47 ++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 46 deletions(-) diff --git a/src/script/block.rs b/src/script/block.rs index da54dd5..bb9049a 100644 --- a/src/script/block.rs +++ b/src/script/block.rs @@ -728,45 +728,49 @@ impl RStatementEnum { } } Self::While(c) => loop { - // While loops blocks can return a bool (false to break from the loop) or a 0-1 length tuple (0-length => continue, 1-length => break with value) - match c.run(vars, libs).data { - VDataEnum::Bool(v) => { - if !v { - break VDataEnum::Tuple(vec![]).to(); - } - } - VDataEnum::Tuple(v) if v.len() == 0 => (), - VDataEnum::Tuple(v) if v.len() == 1 => break v[0].clone(), - _ => unreachable!(), + // While loops will break if the value matches. + if let Some(break_val) = c.run(vars, libs).data.matches() { + break break_val; } }, Self::For(v, c, b) => { + // matching values also break with value from a for loop. let c = c.run(vars, libs); let mut vars = vars.clone(); let mut in_loop = |c| { vars[*v] = Arc::new(Mutex::new(c)); - b.run(&vars, libs); + b.run(&vars, libs) }; + let mut oval = VDataEnum::Tuple(vec![]).to(); match c.data { VDataEnum::Int(v) => { for i in 0..v { - in_loop(VDataEnum::Int(i).to()); + if let Some(v) = in_loop(VDataEnum::Int(i).to()).data.matches() { + oval = v; + break; + } } } VDataEnum::String(v) => { for ch in v.chars() { - in_loop(VDataEnum::String(ch.to_string()).to()) + if let Some(v) = in_loop(VDataEnum::String(ch.to_string()).to()).data.matches() { + oval = v; + break; + } } } VDataEnum::Tuple(v) | VDataEnum::List(_, v) => { for v in v { - in_loop(v) + if let Some(v) = in_loop(v).data.matches() { + oval = v; + break; + } } } _ => unreachable!(), } - VDataEnum::Tuple(vec![]).to() + oval } Self::Switch(switch_on, cases) => { let switch_on = switch_on.run(vars, libs); @@ -782,12 +786,8 @@ impl RStatementEnum { } Self::Match(match_on, cases) => 'm: { for (case_condition, case_action) in cases { - // [t] => Some(t), t => Some(t), [] => None - if let Some(v) = match case_condition.run(vars, libs).data { - VDataEnum::Tuple(mut tuple) => tuple.pop(), - VDataEnum::Bool(v) => if v { Some(VDataEnum::Bool(v).to()) } else { None }, - other => Some(other.to()), - } { + // [t] => Some(t), t => Some(t), [] | false => None + if let Some(v) = case_condition.run(vars, libs).data.matches() { let og = { std::mem::replace(&mut *vars[*match_on].lock().unwrap(), v) }; @@ -837,33 +837,10 @@ impl RStatementEnum { } } Self::While(c) => { - let mut output_types = VType { types: vec![] }; - for t in c.out().types { - match t { - VSingleType::Bool => { - output_types = output_types | VSingleType::Tuple(vec![]).to(); - } - VSingleType::Tuple(mut t) => { - if !t.is_empty() { - if t.len() != 1 { - unreachable!("while loop with tuple of length {}>1.", t.len()); - } - output_types = output_types | t.pop().unwrap(); - } - } - _ => unreachable!( - "while loop statement didn't return bool or 0-1 length tuple." - ), - } - } - output_types + c.out().matches().1 } Self::For(_, _, b) => { - // returns the return value from the last iteration or nothing if there was no iteration - b.out() - | VType { - types: vec![VSingleType::Tuple(vec![])], - } + VSingleType::Tuple(vec![]).to() | b.out().matches().1 } Self::BuiltinFunction(f, args) => f.returns(args.iter().map(|rs| rs.out()).collect()), Self::Switch(switch_on, cases) => { diff --git a/src/script/val_data.rs b/src/script/val_data.rs index 6d91034..6c35254 100644 --- a/src/script/val_data.rs +++ b/src/script/val_data.rs @@ -77,7 +77,54 @@ impl VDataEnum { Self::Reference(r) => r.lock().unwrap().get(i), } } + pub fn matches_ref_bool(&self) -> bool { + match self { + VDataEnum::Tuple(v) => !v.is_empty(), + VDataEnum::Bool(false) => false, + _ => true, + } + } + pub fn matches(self) -> Option { + match self { + VDataEnum::Tuple(mut tuple) => tuple.pop(), + VDataEnum::Bool(v) => { + if v { + Some(VDataEnum::Bool(v).to()) + } else { + None + } + } + other => Some(other.to()), + } + } } +impl VSingleType { + /// returns (can_fail_to_match, matches_as) + pub fn matches(&self) -> (bool, VType) { + match self { + Self::Tuple(v) => match v.first() { + Some(v) => (false, v.clone()), + None => (true, VType { types: vec![] }), + }, + Self::Bool => (true, Self::Bool.to()), + v => (false, v.clone().to()), + } + } +} +impl VType { + /// returns (can_fail_to_match, matches_as) + pub fn matches(&self) -> (bool, VType) { + let mut can_fail = false; + let mut matches_as = VType { types: vec![] }; + for t in self.types.iter() { + let (f, t) = t.matches(); + can_fail |= f; + matches_as = matches_as | t; + } + (can_fail, matches_as) + } +} + #[derive(Clone)] pub struct VDataThread(Arc>); impl VDataThread {