use parser::{Expression, WhileCondition, Statement};
use instructions::Instructions;
use memory::MemoryLayout;
use super::errors::Error;
use super::statements::expand;
use super::input::read_input;
pub fn while_loop(
instructions: &mut Instructions,
mem: &mut MemoryLayout,
condition: WhileCondition,
body: Vec<Statement>,
) -> Result<(), Error> {
loop_condition(instructions, mem, &condition)?;
instructions.jump_forward_if_zero();
loop_body(instructions, mem, body)?;
loop_condition(instructions, mem, &condition)?;
instructions.jump_backward_unless_zero();
Ok(())
}
pub fn loop_condition(
instructions: &mut Instructions,
mem: &mut MemoryLayout,
condition: &WhileCondition,
) -> Result<(), Error> {
let size = match condition {
&WhileCondition::Input {ref name, slice} => {
if slice.is_some() {
mem.undeclare(name);
}
read_input(instructions, mem, name.clone(), slice)?;
let (position, size) = mem.get_cell_contents(name).expect("read_input didn't declare name");
instructions.move_right_by(position);
size
},
&WhileCondition::Expression(Expression::StringLiteral(_)) => {
return Err(Error::LoopStringLiteralUnsupported {});
},
&WhileCondition::Expression(Expression::Identifier(ref name)) => {
let (position, size) = mem.get_cell_contents(name).ok_or_else(|| Error::UndeclaredIdentifier {name: name.clone()})?;
instructions.move_right_by(position);
size
},
};
if size != 1 {
return Err(Error::ConditionSizeInvalid {
expected: 1,
actual: size,
});
}
Ok(())
}
fn loop_body(
instructions: &mut Instructions,
mem: &mut MemoryLayout,
body: Vec<Statement>,
) -> Result<(), Error> {
for stmt in body {
expand(instructions, mem, stmt)?;
}
Ok(())
}