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("IP");
125 self.emit(&Self::encode_int(n, IntPadding::NoPadding));
126 self.expect('}').ok_or("Skip failed to terminate")?;
127 }
128 Some('?') => {
129 self.expect('{').ok_or("Search followed by non-?")?;
130 let s = self.read_to("}").ok_or("Search failed to terminate")?;
131 self.emit("IFF");
132 self.emit_consts(&s);
133 self.expect('}').ok_or("Search failed to terminate")?;
134 }
135 Some('(') => self.emit("IIP"),
136 Some(')') => self.emit("IIC"),
137 Some(';') => self.emit("IIC"),
138 Some('"') => {
139 let n = self.read_to("\",").ok_or("Reference failed terminate")?;
140 let n = Self::parse_int(&n).ok_or("Reference group index invalid")?;
141 let l = match self.iter.next() {
142 Some('"') => "0",
143 Some(',') => &self.read_to("\",").ok_or("Reference failed to terminate")?,
144 _ => return Err("Reference failed to terminate"),
145 };
146 let l = Self::parse_int(&l).ok_or("Reference level invalid")?;
147 self.emit("IP");
148 self.emit(&Self::encode_int(l, IntPadding::NoPadding));
149 self.emit(&Self::encode_int(n, IntPadding::NoPadding));
150 }
151 Some('|') => {
152 let n = self.read_to("|").ok_or("Length failed to terminate")?;
153 let n = Self::parse_int(&n).ok_or("Length group index invalid")?;
154 self.emit("IIP");
155 self.emit(&Self::encode_int(n, IntPadding::NoPadding));
156 }
157 Some('n') => {
158 self.expect('{');
159 let n = self
160 .read_to("},")
161 .ok_or("Int constant failed to terminate")?;
162 let n = Self::parse_int(&n).ok_or("Int constant invalid")?;
163 match self.iter.next() {
164 Some('}') => {
165 self.emit(&Self::encode_int(n, IntPadding::NoPadding));
166 }
167 Some(',') => {
168 let pad = self
169 .read_to("}")
170 .ok_or("Int constant failed to terminate")?;
171 let pad =
172 Self::parse_int(&pad).ok_or("Int constant padding invalid")?;
173 self.emit_consts(&Self::encode_int(n, IntPadding::PaddedTo(pad)));
174 self.expect('}').ok_or("Int constant failed to terminate")?;
175 }
176 _ => return Err("Int constant failed to terminate"),
177 };
178 }
179 Some(' ') | Some('\n') => {}
180 None => return Ok(self.output),
181 Some(c) => {
182 println!("{}", c);
183 return Err("Invalid character");
184 }
185 }
186 }
187 }
188}
189
190// TODO: Tests