ICFP 2007 Contest: https://web.archive.org/web/20090301164728/https://save-endo.cs.uu.nl/
1use std::iter::Peekable; 2use std::str::Chars; 3 4pub type Error = &'static str; 5 6pub fn assemble(asm: &str) -> Result<Vec<u8>, Error> { 7 Assembler::new(asm).assemble() 8} 9 10struct Assembler<'a> { 11 iter: Peekable<Chars<'a>>, 12 output: Vec<u8>, 13} 14 15enum IntPadding { 16 NoPadding, 17 PaddedTo(usize), 18} 19 20impl<'a> Assembler<'a> { 21 fn new(buf: &'a str) -> Assembler<'a> { 22 Assembler { 23 iter: buf.chars().peekable(), 24 output: Vec::new(), 25 } 26 } 27 28 fn expect(&mut self, c: char) -> Option<()> { 29 match self.iter.next() { 30 Some(d) => { 31 if c == d { 32 Some(()) 33 } else { 34 None 35 } 36 } 37 None => None, 38 } 39 } 40 41 fn emit(&mut self, s: &str) { 42 self.output.extend_from_slice(s.as_bytes()); 43 } 44 45 fn read_to(&mut self, any_of: &str) -> Option<String> { 46 let mut s = String::new(); 47 loop { 48 if let Some(c) = self.iter.peek() 49 && any_of.contains(*c) 50 { 51 return Some(s); 52 } 53 54 match self.iter.next() { 55 Some(c) => s.push(c), 56 None => return None, 57 } 58 } 59 } 60 61 fn parse_int(s: &str) -> Option<usize> { 62 let is_hex = s.starts_with("0x"); 63 let base = if is_hex { 16 } else { 10 }; 64 let mut ret = 0; 65 let mut iter = s.chars(); 66 if is_hex { 67 // TODO: advance_by? 68 iter.nth(1); 69 } 70 71 for c in iter { 72 ret *= base; 73 ret += c.to_digit(base)?; 74 } 75 76 return Some(ret as usize); 77 } 78 79 fn encode_int(mut n: usize, p: IntPadding) -> String { 80 let mut s = String::new(); 81 while n > 0 { 82 if n % 2 == 1 { 83 s += "C"; 84 } else { 85 s += "I"; 86 } 87 88 n /= 2; 89 } 90 91 if let IntPadding::PaddedTo(p) = p { 92 for _ in s.len()..(p - 1) { 93 s += "I"; 94 } 95 } 96 97 s += "P"; 98 return s; 99 } 100 101 fn emit_consts(&mut self, s: &str) { 102 for c in s.chars() { 103 match c { 104 'I' => self.emit("C"), 105 'C' => self.emit("F"), 106 'F' => self.emit("P"), 107 'P' => self.emit("IC"), 108 _ => {} 109 } 110 } 111 } 112 113 fn assemble(mut self) -> Result<Vec<u8>, Error> { 114 loop { 115 match self.iter.next() { 116 Some('I') => self.emit("C"), 117 Some('C') => self.emit("F"), 118 Some('F') => self.emit("P"), 119 Some('P') => self.emit("IC"), 120 Some('!') => { 121 self.expect('{').ok_or("Skip followed by non-{")?; 122 let n = self.read_to("}").ok_or("Skip failed to terminate")?; 123 let n = Self::parse_int(&n).ok_or("Invalid int inside skip")?; 124 self.emit(&Self::encode_int(n, IntPadding::NoPadding)); 125 self.expect('}').ok_or("Skip failed to terminate")?; 126 } 127 Some('?') => { 128 self.expect('{').ok_or("Search followed by non-?")?; 129 let s = self.read_to("}").ok_or("Search failed to terminate")?; 130 self.emit("IFF"); 131 self.emit_consts(&s); 132 self.expect('}').ok_or("Search failed to terminate")?; 133 } 134 Some('(') => self.emit("IIP"), 135 Some(')') => self.emit("IIC"), 136 Some(';') => self.emit("IIC"), 137 Some('"') => { 138 let n = self.read_to("\",").ok_or("Reference failed terminate")?; 139 let n = Self::parse_int(&n).ok_or("Reference group index invalid")?; 140 let l = match self.iter.next() { 141 Some('"') => "0", 142 Some(',') => &self.read_to("\",").ok_or("Reference failed to terminate")?, 143 _ => return Err("Reference failed to terminate"), 144 }; 145 let l = Self::parse_int(&l).ok_or("Reference level invalid")?; 146 self.emit("IP"); 147 self.emit(&Self::encode_int(l, IntPadding::NoPadding)); 148 self.emit(&Self::encode_int(n, IntPadding::NoPadding)); 149 } 150 Some('|') => { 151 let n = self.read_to("|").ok_or("Length failed to terminate")?; 152 let n = Self::parse_int(&n).ok_or("Length group index invalid")?; 153 self.emit("IIP"); 154 self.emit(&Self::encode_int(n, IntPadding::NoPadding)); 155 } 156 Some('n') => { 157 self.expect('{'); 158 let n = self 159 .read_to("},") 160 .ok_or("Int constant failed to terminate")?; 161 let n = Self::parse_int(&n).ok_or("Int constant invalid")?; 162 match self.iter.next() { 163 Some('}') => { 164 self.emit(&Self::encode_int(n, IntPadding::NoPadding)); 165 } 166 Some(',') => { 167 let pad = self 168 .read_to("}") 169 .ok_or("Int constant failed to terminate")?; 170 let pad = 171 Self::parse_int(&pad).ok_or("Int constant padding invalid")?; 172 self.emit_consts(&Self::encode_int(n, IntPadding::PaddedTo(pad))); 173 self.expect('}').ok_or("Int constant failed to terminate")?; 174 } 175 _ => return Err("Int constant failed to terminate"), 176 }; 177 } 178 Some(' ') | Some('\n') => {} 179 None => return Ok(self.output), 180 Some(c) => { 181 println!("{}", c); 182 return Err("Invalid character"); 183 } 184 } 185 } 186 } 187} 188 189// TODO: Tests