| 169 | |
| 170 | impl fmt::Debug for Program { |
| 171 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 172 | use self::Inst::*; |
| 173 | |
| 174 | fn with_goto(cur: usize, goto: usize, fmtd: String) -> String { |
| 175 | if goto == cur + 1 { |
| 176 | fmtd |
| 177 | } else { |
| 178 | format!("{} (goto: {})", fmtd, goto) |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | fn visible_byte(b: u8) -> String { |
| 183 | use std::ascii::escape_default; |
| 184 | let escaped = escape_default(b).collect::<Vec<u8>>(); |
| 185 | String::from_utf8_lossy(&escaped).into_owned() |
| 186 | } |
| 187 | |
| 188 | for (pc, inst) in self.iter().enumerate() { |
| 189 | match *inst { |
| 190 | Match(slot) => { |
| 191 | write!(f, "{:04} Match({:?})", pc, slot)? |
| 192 | } |
| 193 | Save(ref inst) => { |
| 194 | let s = format!("{:04} Save({})", pc, inst.slot); |
| 195 | write!(f, "{}", with_goto(pc, inst.goto, s))?; |
| 196 | } |
| 197 | Split(ref inst) => { |
| 198 | write!( |
| 199 | f, "{:04} Split({}, {})", pc, inst.goto1, inst.goto2)?; |
| 200 | } |
| 201 | EmptyLook(ref inst) => { |
| 202 | let s = format!("{:?}", inst.look); |
| 203 | write!(f, "{:04} {}", pc, with_goto(pc, inst.goto, s))?; |
| 204 | } |
| 205 | Char(ref inst) => { |
| 206 | let s = format!("{:?}", inst.c); |
| 207 | write!(f, "{:04} {}", pc, with_goto(pc, inst.goto, s))?; |
| 208 | } |
| 209 | Ranges(ref inst) => { |
| 210 | let ranges = inst.ranges |
| 211 | .iter() |
| 212 | .map(|r| format!("{:?}-{:?}", r.0, r.1)) |
| 213 | .collect::<Vec<String>>() |
| 214 | .join(", "); |
| 215 | write!( |
| 216 | f, "{:04} {}", pc, with_goto(pc, inst.goto, ranges))?; |
| 217 | } |
| 218 | Bytes(ref inst) => { |
| 219 | let s = format!( |
| 220 | "Bytes({}, {})", |
| 221 | visible_byte(inst.start), |
| 222 | visible_byte(inst.end)); |
| 223 | write!(f, "{:04} {}", pc, with_goto(pc, inst.goto, s))?; |
| 224 | } |
| 225 | } |
| 226 | if pc == self.start { |
| 227 | write!(f, " (start)")?; |
| 228 | } |