changed while loop break to use matching (any matching value breaks) and added the same break functionality to for loops.

This commit is contained in:
Dummi26 2023-03-30 19:11:21 +02:00
parent 52973eb0f8
commit 260e42d4a7
2 changed files with 70 additions and 46 deletions

View File

@ -728,45 +728,49 @@ impl RStatementEnum {
} }
} }
Self::While(c) => loop { 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) // While loops will break if the value matches.
match c.run(vars, libs).data { if let Some(break_val) = c.run(vars, libs).data.matches() {
VDataEnum::Bool(v) => { break break_val;
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!(),
} }
}, },
Self::For(v, c, b) => { Self::For(v, c, b) => {
// matching values also break with value from a for loop.
let c = c.run(vars, libs); let c = c.run(vars, libs);
let mut vars = vars.clone(); let mut vars = vars.clone();
let mut in_loop = |c| { let mut in_loop = |c| {
vars[*v] = Arc::new(Mutex::new(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 { match c.data {
VDataEnum::Int(v) => { VDataEnum::Int(v) => {
for i in 0..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) => { VDataEnum::String(v) => {
for ch in v.chars() { 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) => { VDataEnum::Tuple(v) | VDataEnum::List(_, v) => {
for v in v { for v in v {
in_loop(v) if let Some(v) = in_loop(v).data.matches() {
oval = v;
break;
}
} }
} }
_ => unreachable!(), _ => unreachable!(),
} }
VDataEnum::Tuple(vec![]).to() oval
} }
Self::Switch(switch_on, cases) => { Self::Switch(switch_on, cases) => {
let switch_on = switch_on.run(vars, libs); let switch_on = switch_on.run(vars, libs);
@ -782,12 +786,8 @@ impl RStatementEnum {
} }
Self::Match(match_on, cases) => 'm: { Self::Match(match_on, cases) => 'm: {
for (case_condition, case_action) in cases { for (case_condition, case_action) in cases {
// [t] => Some(t), t => Some(t), [] => None // [t] => Some(t), t => Some(t), [] | false => None
if let Some(v) = match case_condition.run(vars, libs).data { if let Some(v) = case_condition.run(vars, libs).data.matches() {
VDataEnum::Tuple(mut tuple) => tuple.pop(),
VDataEnum::Bool(v) => if v { Some(VDataEnum::Bool(v).to()) } else { None },
other => Some(other.to()),
} {
let og = { let og = {
std::mem::replace(&mut *vars[*match_on].lock().unwrap(), v) std::mem::replace(&mut *vars[*match_on].lock().unwrap(), v)
}; };
@ -837,33 +837,10 @@ impl RStatementEnum {
} }
} }
Self::While(c) => { Self::While(c) => {
let mut output_types = VType { types: vec![] }; c.out().matches().1
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
} }
Self::For(_, _, b) => { Self::For(_, _, b) => {
// returns the return value from the last iteration or nothing if there was no iteration VSingleType::Tuple(vec![]).to() | b.out().matches().1
b.out()
| VType {
types: vec![VSingleType::Tuple(vec![])],
}
} }
Self::BuiltinFunction(f, args) => f.returns(args.iter().map(|rs| rs.out()).collect()), Self::BuiltinFunction(f, args) => f.returns(args.iter().map(|rs| rs.out()).collect()),
Self::Switch(switch_on, cases) => { Self::Switch(switch_on, cases) => {

View File

@ -77,7 +77,54 @@ impl VDataEnum {
Self::Reference(r) => r.lock().unwrap().get(i), 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<VData> {
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)] #[derive(Clone)]
pub struct VDataThread(Arc<Mutex<VDataThreadEnum>>); pub struct VDataThread(Arc<Mutex<VDataThreadEnum>>);
impl VDataThread { impl VDataThread {