changeset 703:81232dac8136

ecl: simplify parsing with more combinators.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 23 Aug 2019 17:37:22 +0200
parents 718348c7608e
children 84af5bedbde4
files src/th06/ecl.rs src/th06/ecl_vm.rs src/th06/enemy.rs
diffstat 3 files changed, 32 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/src/th06/ecl.rs
+++ b/src/th06/ecl.rs
@@ -2,8 +2,9 @@
 
 use nom::{
     IResult,
-    bytes::complete::take_while_m_n,
     number::complete::{le_u8, le_u16, le_u32, le_i16, le_i32, le_f32},
+    sequence::tuple,
+    multi::many_m_n,
 };
 use encoding_rs::SHIFT_JIS;
 use bitflags::bitflags;
@@ -12,19 +13,19 @@ bitflags! {
     /// Bit flags describing the current difficulty level.
     pub struct Rank: u16 {
         /// Easy mode.
-        const Easy = 0x100;
+        const EASY = 0x100;
 
         /// Normal mode.
-        const Normal = 0x200;
+        const NORMAL = 0x200;
 
         /// Hard mode.
-        const Hard = 0x400;
+        const HARD = 0x400;
 
         /// Lunatic mode.
-        const Lunatic = 0x800;
+        const LUNATIC = 0x800;
 
         /// Any or all modes.
-        const All = 0xff00;
+        const ALL = 0xff00;
     }
 }
 
@@ -33,10 +34,10 @@ impl std::str::FromStr for Rank {
 
     fn from_str(s: &str) -> Result<Rank, Self::Err> {
         Ok(match s {
-            "easy" => Rank::Easy,
-            "normal" => Rank::Normal,
-            "hard" => Rank::Hard,
-            "lunatic" => Rank::Lunatic,
+            "easy" => Rank::EASY,
+            "normal" => Rank::NORMAL,
+            "hard" => Rank::HARD,
+            "lunatic" => Rank::LUNATIC,
             _ => return Err(format!("unknown rank {}", s))
         })
     }
@@ -329,52 +330,40 @@ fn parse_ecl(input: &[u8]) -> IResult<&[
     let i = input;
 
     let (i, sub_count) = le_u16(i)?;
-    let (mut i, main_count) = le_u16(i)?;
+    let sub_count = sub_count as usize;
+    let (i, main_count) = le_u16(i)?;
     assert_eq!(main_count, 0);
 
-    let mut main_offsets = Vec::new();
-    for _ in 0..3 {
-        let (i2, offset) = le_u32(i)?;
-        main_offsets.push(offset as usize);
-        i = i2;
-    }
-
-    let mut sub_offsets = Vec::new();
-    for _ in 0..sub_count {
-        let (i2, offset) = le_u32(i)?;
-        sub_offsets.push(offset as usize);
-        i = i2;
-    }
+    let (i, main_offsets) = many_m_n(3, 3, le_u32)(i)?;
+    let (_, sub_offsets) = many_m_n(sub_count, sub_count, le_u32)(i)?;
 
     // Read all subs.
     let mut subs = Vec::new();
-    for offset in sub_offsets {
+    for offset in sub_offsets.into_iter().map(|offset| offset as usize) {
         let mut i = &input[offset..];
         let mut instructions = Vec::new();
         loop {
-            let (i2, time) = le_i32(i)?;
-            let (i2, opcode) = le_u16(i2)?;
+            let (i2, (time, opcode)) = tuple((le_i32, le_u16))(i)?;
             if time == -1 || opcode == 0xffff {
                 break;
             }
 
-            let (i2, size) = le_u16(i2)?;
-            let (i2, rank_mask) = le_u16(i2)?;
+            let (i2, (size, rank_mask, param_mask)) = tuple((le_u16, le_u16, le_u16))(i2)?;
+            let size = size as usize;
             let rank_mask = Rank::from_bits(rank_mask).unwrap();
-            let (i2, param_mask) = le_u16(i2)?;
             // FIXME: this - 12 can trigger a panic, fuzz it!
-            let data = &i2[..size as usize - 12];
+            let data = &i2[..size - 12];
             let (data, instr) = parse_sub_instruction_args(data, opcode)?;
             assert_eq!(data.len(), 0);
             instructions.push(CallSub { time, rank_mask, param_mask, instr });
-            i = &i[size as usize..];
+            i = &i[size..];
         }
         subs.push(Sub { instructions });
     }
 
     // Read all mains (always a single one atm).
     let mut mains = Vec::new();
-    for offset in main_offsets {
+    for offset in main_offsets.into_iter().map(|offset| offset as usize) {
         if offset == 0 {
             break;
         }
@@ -382,20 +371,19 @@ fn parse_ecl(input: &[u8]) -> IResult<&[
         let mut i = &input[offset..];
         let mut instructions = Vec::new();
         loop {
-            let (i2, time) = le_u16(i)?;
-            let (i2, sub) = le_u16(i2)?;
+            let (i2, (time, sub)) = tuple((le_u16, le_u16))(i)?;
             if time == 0xffff && sub == 4 {
                 break;
             }
 
-            let (i2, opcode) = le_u16(i2)?;
-            let (i2, size) = le_u16(i2)?;
+            let (i2, (opcode, size)) = tuple((le_u16, le_u16))(i2)?;
+            let size = size as usize;
             // FIXME: this - 8 can trigger a panic, fuzz it!
-            let data = &i2[..size as usize - 8];
+            let data = &i2[..size - 8];
             let (data, instr) = parse_main_instruction_args(data, opcode)?;
             assert_eq!(data.len(), 0);
             instructions.push(CallMain { time, sub, instr });
-            i = &i[size as usize..];
+            i = &i[size..];
         }
         mains.push(Main { instructions });
     }
--- a/src/th06/ecl_vm.rs
+++ b/src/th06/ecl_vm.rs
@@ -981,7 +981,7 @@ mod tests {
         let anm0 = anms.pop().unwrap();
         let anm0 = Rc::new(RefCell::new(anm0));
         let prng = Rc::new(RefCell::new(Prng::new(0)));
-        let game = Game::new(prng, Rank::Easy);
+        let game = Game::new(prng, Rank::EASY);
         let game = Rc::new(RefCell::new(game));
         let enemy = Enemy::new(Position::new(0., 0.), 500, 0, 640, Rc::downgrade(&anm0), Rc::downgrade(&game));
         (game, enemy)
@@ -992,11 +992,11 @@ mod tests {
         let (game, enemy) = setup();
         let ecl = Ecl { mains: vec![], subs: vec![
             Sub { instructions: vec![
-                CallSub::new(0, Rank::Easy, SubInstruction::Call(1, 13, 12.)),
+                CallSub::new(0, Rank::EASY, SubInstruction::Call(1, 13, 12.)),
             ]},
             Sub { instructions: vec![
-                CallSub::new(0, Rank::Easy, SubInstruction::Noop()),
-                CallSub::new(1, Rank::Easy, SubInstruction::Return()),
+                CallSub::new(0, Rank::EASY, SubInstruction::Noop()),
+                CallSub::new(1, Rank::EASY, SubInstruction::Return()),
             ]},
         ]};
         let mut ecl_runner = EclRunner::new(&ecl, enemy, 0);
--- a/src/th06/enemy.rs
+++ b/src/th06/enemy.rs
@@ -505,7 +505,7 @@ mod tests {
         let anm0 = anms.pop().unwrap();
         let anm0 = Rc::new(RefCell::new(anm0));
         let prng = Rc::new(RefCell::new(Prng::new(0)));
-        let game = Game::new(prng, Rank::Easy);
+        let game = Game::new(prng, Rank::EASY);
         let game = Rc::new(RefCell::new(game));
         let enemy = Enemy::new(Position::new(0., 0.), 500, 0, 640, Rc::downgrade(&anm0), Rc::downgrade(&game));
         let mut enemy = enemy.borrow_mut();