Browse Source

Fix nested loop parsing

master
garritfra 4 years ago
parent
commit
bc9ada397c
  1. 20
      src/main.rs
  2. 58
      src/parser.rs

20
src/main.rs

@ -5,7 +5,7 @@ use instructions::Instruction;
use instructions::OpCode;
fn main() {
let tokens: Vec<OpCode> = lexer::lex("+[--].");
let tokens: Vec<OpCode> = lexer::lex("+[-[.]-].");
let instructions: Vec<Instruction> = parser::parse(tokens);
@ -31,4 +31,22 @@ mod tests {
);
assert_eq!(*instructions.get(2).unwrap(), Instruction::Print);
}
#[test]
fn when_input_contains_nested_loop_then_loops_get_parsed() {
let input = "+[-[++]].";
let tokens = super::lexer::lex(input);
let instructions: Vec<Instruction> = super::parser::parse(tokens);
println!("{:?}", instructions);
assert_eq!(instructions.len(), 3);
assert_eq!(*instructions.get(0).unwrap(), Instruction::Increment);
assert_eq!(
*instructions.get(1).unwrap(),
Instruction::Loop(vec![
Instruction::Decrement,
Instruction::Loop(vec![Instruction::Increment, Instruction::Increment])
],)
);
assert_eq!(*instructions.get(2).unwrap(), Instruction::Print);
}
}

58
src/parser.rs

@ -2,31 +2,53 @@ use crate::instructions::*;
pub fn parse(op_codes: Vec<OpCode>) -> Vec<Instruction> {
let mut instructions: Vec<Instruction> = Vec::new();
let mut loop_stack = 0;
let mut loop_start = 0;
let mut codes = op_codes.iter();
loop {
if let Some(code) = codes.next() {
match code {
OpCode::Increment => instructions.push(Instruction::Increment),
OpCode::Decrement => instructions.push(Instruction::Decrement),
OpCode::MoveRight => instructions.push(Instruction::MoveRight),
OpCode::MoveLeft => instructions.push(Instruction::MoveLeft),
OpCode::Print => instructions.push(Instruction::Print),
OpCode::Read => instructions.push(Instruction::Read),
for (i, code) in op_codes.iter().enumerate() {
if loop_stack == 0 {
let instruction = match code {
OpCode::Increment => Some(Instruction::Increment),
OpCode::Decrement => Some(Instruction::Decrement),
OpCode::MoveRight => Some(Instruction::MoveRight),
OpCode::MoveLeft => Some(Instruction::MoveLeft),
OpCode::Print => Some(Instruction::Print),
OpCode::Read => Some(Instruction::Read),
OpCode::LoopStart => {
let codes_ref = &mut codes;
let loop_opcodes: Vec<OpCode> = codes_ref
.take_while(|x| **x != OpCode::LoopEnd)
.cloned()
.collect();
instructions.push(Instruction::Loop(parse(loop_opcodes)));
loop_start = i;
loop_stack += 1;
None
}
OpCode::LoopEnd => panic!("Extra ] found"),
OpCode::LoopEnd => panic!("Loop ending at #{} has no beginning", i),
};
match instruction {
Some(instruction) => instructions.push(instruction),
None => (),
}
} else {
break;
match code {
OpCode::LoopStart => {
loop_stack += 1;
}
OpCode::LoopEnd => {
loop_stack -= 1;
if loop_stack == 0 {
instructions.push(Instruction::Loop(parse(
op_codes[loop_start + 1..i].to_vec(),
)))
}
}
_ => (),
}
}
}
if loop_stack != 0 {
panic!(
"loop that starts at #{} has no matching ending!",
loop_start
);
}
instructions
}

Loading…
Cancel
Save