use std::sync::Arc;
use arcstr::ArcStr;
use imbl::Vector;
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use crate::{model::Graph, runtime::{instruction::{Instruction, Instructions}, instructions::{Base, ConsumeStack}, proc::ProcEnv, Error}};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct IfIns {
pub if_test: Option<Arc<dyn Instruction>>,
pub if_ins: Vector<Arc<dyn Instruction>>,
pub el_ins: Vector<Arc<dyn Instruction>>, }
#[typetag::serde(name = "IfIns")]
impl Instruction for IfIns {
fn exec(&self, _env: &mut ProcEnv, _graph: &mut Graph) -> Result<Option<Instructions>, Error> {
let mut instructions = Instructions::default();
if let Some(test) = &self.if_test {
instructions.push(test.clone());
}
let if_tag: ArcStr = nanoid!(10).into();
let else_tag: ArcStr = nanoid!(10).into();
instructions.push(Arc::new(Base::CtrlForwardToIfNotTruthy(else_tag.clone(), ConsumeStack::Consume)));
instructions.append(&self.if_ins);
instructions.push(Arc::new(Base::CtrlForwardTo(if_tag.clone())));
instructions.push(Arc::new(Base::Tag(else_tag)));
instructions.append(&self.el_ins);
instructions.push(Arc::new(Base::Tag(if_tag)));
Ok(Some(instructions))
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use arcstr::literal;
use crate::{model::Graph, runtime::{instructions::{ifs::IfIns, Base}, Runtime, Val}};
#[test]
fn if_true() {
let mut ins = IfIns::default();
ins.if_test = Some(Arc::new(Base::Literal(Val::Bool(true))));
ins.if_ins.push_back(Arc::new(Base::Literal(Val::Str(literal!("a")))));
ins.el_ins.push_back(Arc::new(Base::Literal(Val::Str(literal!("b")))));
let mut graph = Graph::default();
let res = Runtime::eval(&mut graph, Arc::new(ins)).expect("expected pass");
assert_eq!(res, "a".into());
}
#[test]
fn if_false() {
let mut ins = IfIns::default();
ins.if_test = Some(Arc::new(Base::Literal(Val::Bool(false))));
ins.if_ins.push_back(Arc::new(Base::Literal(Val::Str(literal!("a")))));
ins.el_ins.push_back(Arc::new(Base::Literal(Val::Str(literal!("b")))));
let mut graph = Graph::default();
let res = Runtime::eval(&mut graph, Arc::new(ins)).expect("expected pass");
assert_eq!(res, "b".into());
}
}