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