1use crate::il::{BinOp, Region, Term};
13use crate::bytecode::{Assembly,Builder,Instruction,StructuredSection};
14use crate::bytecode::Instruction::*;
15use crate::util::*;
16
17type Result = std::result::Result<(), CompilerError>;
18
19#[derive(Debug)]
24pub enum CompilerError {
25 LiteralOverflow,
27 InvalidMemoryAccess,
29 InvalidLVal,
31}
32
33pub struct Compiler {
38 builder: Builder,
40 labels: usize
42}
43
44impl Compiler {
45 pub fn new() -> Self {
46 Self {
47 builder: Builder::new(),
48 labels: 0
49 }
50 }
51
52 pub fn to_assembly(self) -> Assembly {
53 let insns = self.builder.to_insns();
54 let code = StructuredSection::Code(insns);
55 Assembly::new(vec![code])
56 }
57
58 pub fn translate(&mut self, term: &Term) -> Result {
59 match term {
60 Term::Assert(e) => self.translate_assert(e),
62 Term::Assignment(e1, e2) => self.translate_assignment(e1, e2),
63 Term::Fail => self.translate_fail(),
64 Term::Goto(l) => self.translate_goto(l),
65 Term::IfGoto(e, l) => self.translate_ifgoto(e, l),
66 Term::Label(l) => self.translate_label(l),
67 Term::Return(es) => self.translate_return(es),
68 Term::Revert(es) => self.translate_revert(es),
69 Term::Succeed(es) => self.translate_succeed(es),
70 Term::Stop => self.translate_stop(),
71 Term::Binary(bop, e1, e2) => self.translate_binary(*bop, e1, e2),
73 Term::Call(n,es) => self.translate_call(n,es),
74 Term::ArrayAccess(src, index) => self.translate_array_access(src, index),
75 Term::MemoryAccess(_) => Err(CompilerError::InvalidMemoryAccess),
76 Term::Int(bytes) => self.translate_literal(bytes, 10),
78 Term::Hex(bytes) => self.translate_literal(bytes, 16),
79 }
81 }
82
83 fn fresh_label(&mut self) -> String {
84 let lab = format!("lab{}",self.labels);
85 self.labels += 1;
86 lab
87 }
88
89 fn translate_assert(&mut self, expr: &Term) -> Result {
94 let lab = self.fresh_label();
96 self.translate_conditional(expr, Some(&lab), None)?;
98 self.builder.push(PUSH(vec![0x00]));
100 self.builder.push(PUSH(vec![0x00]));
101 self.builder.push(REVERT);
102 self.builder.mark_label(&lab).unwrap();
104 self.builder.push(JUMPDEST);
105 Ok(())
107 }
108
109 fn translate_assignment(&mut self, lhs: &Term, rhs: &Term) -> Result {
110 self.translate(rhs)?;
112 match lhs {
114 Term::ArrayAccess(src, idx) => {
115 self.translate_assignment_array(src, idx)?;
116 }
117 _ => {
118 return Err(CompilerError::InvalidLVal);
119 }
120 }
121 Ok(())
123 }
124
125 fn translate_assignment_array(&mut self, src: &Term, index: &Term) -> Result {
126 match src {
127 Term::MemoryAccess(r) => self.translate_assignment_memory(*r, index),
128 _ => Err(CompilerError::InvalidMemoryAccess),
129 }
130 }
131
132 fn translate_assignment_memory(&mut self, region: Region, address: &Term) -> Result {
133 self.translate(address)?;
135 match region {
137 Region::Memory => self.builder.push(MSTORE),
138 Region::Storage => self.builder.push(SSTORE),
139 _ => {
140 return Err(CompilerError::InvalidMemoryAccess);
141 }
142 };
143 Ok(())
145 }
146
147 fn translate_call(&mut self, name: &str, exprs: &[Term]) -> Result {
148 let retlab = self.fresh_label();
149 let retlab_index = self.builder.get_label(&retlab);
150 let name_index = self.builder.get_label(name);
151 for e in exprs { self.translate(e)?; }
153 self.builder.push_labeled(PUSH(label_bytes(retlab_index)));
155 self.builder.push_labeled(PUSH(label_bytes(name_index)));
157 self.builder.push(JUMP);
159 self.builder.mark_label(&retlab).unwrap();
161 self.builder.push(JUMPDEST);
162 Ok(())
163 }
164
165 fn translate_fail(&mut self) -> Result {
166 self.builder.push(PUSH(vec![0x00]));
167 self.builder.push(PUSH(vec![0x00]));
168 self.builder.push(REVERT);
169 Ok(())
170 }
171
172 fn translate_goto(&mut self, label: &str) -> Result {
173 let label_index = self.builder.get_label(label);
174 self.builder.push_labeled(PUSH(label_bytes(label_index)));
176 self.builder.push(JUMP);
177 Ok(())
179 }
180
181 fn translate_ifgoto(&mut self, expr: &Term, label: &str) -> Result {
182 self.translate_conditional(expr, Some(label), None)
184 }
185
186 fn translate_label(&mut self, label: &str) -> Result {
187 self.builder.mark_label(label).unwrap();
189 self.builder.push(JUMPDEST);
190 Ok(())
192 }
193
194 fn translate_return(&mut self, exprs: &[Term]) -> Result {
195 if !exprs.is_empty() {
196 for e in exprs.iter().skip(1) { self.translate(e)?; }
198 self.translate(&exprs[0])?;
200 self.builder.push(SWAP(exprs.len() as u8));
202 }
203 self.builder.push(JUMP);
205 Ok(())
207 }
208
209 fn translate_revert(&mut self, exprs: &[Term]) -> Result {
210 self.translate_succeed_revert(REVERT, exprs)
211 }
212
213 fn translate_succeed(&mut self, exprs: &[Term]) -> Result {
214 if exprs.is_empty() {
215 self.builder.push(STOP);
216 Ok(())
217 } else {
218 self.translate_succeed_revert(RETURN, exprs)
219 }
220 }
221
222 fn translate_succeed_revert(&mut self, insn: Instruction, exprs: &[Term]) -> Result {
223 if exprs.is_empty() {
224 self.builder.push(PUSH(vec![0]));
225 self.builder.push(PUSH(vec![0]));
226 } else {
227 for (i,e) in exprs.iter().enumerate() {
228 let addr = (i * 0x20) as u128;
229 self.translate(e)?;
230 self.builder.push(make_push(addr)?);
231 self.builder.push(MSTORE);
232 }
233 let len = (exprs.len() * 0x20) as u128;
234 self.builder.push(PUSH(vec![0]));
235 self.builder.push(make_push(len)?);
236 }
237 self.builder.push(insn);
238 Ok(())
239 }
240
241 fn translate_stop(&mut self) -> Result {
242 self.builder.push(STOP);
243 Ok(())
244 }
245
246 fn translate_conditional(&mut self, expr: &Term, true_lab: Option<&str>, false_lab: Option<&str>) -> Result {
261 match expr {
262 Term::Binary(BinOp::LogicalAnd, l, r) => {
263 self.translate_conditional_conjunct(l, r, true_lab, false_lab)
264 }
265 Term::Binary(BinOp::LogicalOr, l, r) => {
266 self.translate_conditional_disjunct(l, r, true_lab, false_lab)
267 }
268 _ => self.translate_conditional_other(expr, true_lab, false_lab),
269 }
270 }
271
272 fn translate_conditional_conjunct(&mut self, lhs: &Term, rhs: &Term, true_lab: Option<&str>, false_lab: Option<&str>) -> Result {
276 match (true_lab, false_lab) {
277 (Some(_), None) => {
278 let lab = self.fresh_label();
280 self.translate_conditional(lhs, None, Some(&lab))?;
281 self.translate_conditional(rhs, true_lab, None)?;
282 self.builder.mark_label(&lab).unwrap();
283 self.builder.push(JUMPDEST);
284 }
285 (None, Some(_)) => {
286 self.translate_conditional(lhs, None, false_lab)?;
288 self.translate_conditional(rhs, true_lab, false_lab)?;
289 }
290 (_, _) => unreachable!(),
291 }
292 Ok(())
294 }
295
296 fn translate_conditional_disjunct(&mut self, lhs: &Term, rhs: &Term, true_lab: Option<&str>, false_lab: Option<&str>) -> Result {
300 match (true_lab, false_lab) {
301 (None, Some(_)) => {
302 let lab = self.fresh_label();
304 self.translate_conditional(lhs, Some(&lab), None)?;
305 self.translate_conditional(rhs, None, false_lab)?;
306 self.builder.mark_label(&lab).unwrap();
307 self.builder.push(JUMPDEST);
308 }
309 (Some(_), None) => {
310 self.translate_conditional(lhs, true_lab, None)?;
312 self.translate_conditional(rhs, true_lab, false_lab)?;
313 }
314 (_, _) => unreachable!(),
315 }
316 Ok(())
318 }
319
320 fn translate_conditional_other(&mut self, expr: &Term, true_lab: Option<&str>, false_lab: Option<&str>) -> Result {
324 self.translate(expr)?;
326 match (true_lab, false_lab) {
328 (Some(lab), None) => {
329 let label_index = self.builder.get_label(lab);
330 self.builder.push_labeled(PUSH(label_bytes(label_index)));
331 self.builder.push(JUMPI);
332 }
333 (None, Some(lab)) => {
334 let label_index = self.builder.get_label(lab);
335 self.builder.push(ISZERO);
336 self.builder.push_labeled(PUSH(label_bytes(label_index)));
337 self.builder.push(JUMPI);
338 }
339 (_, _) => {
340 unreachable!("")
341 }
342 }
343 Ok(())
345 }
346
347 fn translate_binary(&mut self, bop: BinOp, lhs: &Term, rhs: &Term) -> Result {
354 match bop {
355 BinOp::LogicalAnd | BinOp::LogicalOr => {
356 self.translate_logical_connective(bop, lhs, rhs)
357 }
358 _ => self.translate_binary_arithmetic(bop, lhs, rhs),
359 }
360 }
361
362 fn translate_logical_connective(&mut self, bop: BinOp, lhs: &Term, rhs: &Term) -> Result {
366 self.translate(lhs)?;
367 self.builder.push(DUP(1));
368 if bop == BinOp::LogicalAnd {
369 self.builder.push(ISZERO);
370 }
371 let lab = self.fresh_label();
373 let lab_index = self.builder.get_label(&lab);
374 self.builder.push_labeled(PUSH(label_bytes(lab_index)));
375 self.builder.push(JUMPI);
376 self.builder.push(POP);
377 self.translate(rhs)?;
378 self.builder.mark_label(&lab).unwrap();
379 self.builder.push(JUMPDEST);
380 Ok(())
382 }
383
384 fn translate_binary_arithmetic(&mut self, bop: BinOp, lhs: &Term, rhs: &Term) -> Result {
389 self.translate(rhs)?;
390 self.translate(lhs)?;
391 match bop {
393 BinOp::Add => self.builder.push(ADD),
395 BinOp::Subtract => self.builder.push(SUB),
396 BinOp::Divide => self.builder.push(DIV),
397 BinOp::Multiply => self.builder.push(MUL),
398 BinOp::Remainder => self.builder.push(MOD),
399 BinOp::Equals => self.builder.push(EQ),
400 BinOp::LessThan => self.builder.push(LT),
401 BinOp::GreaterThan => self.builder.push(GT),
402 BinOp::NotEquals => {
404 self.builder.push(EQ);
405 self.builder.push(ISZERO);
406 }
407 BinOp::LessThanOrEquals => {
408 self.builder.push(GT);
409 self.builder.push(ISZERO);
410 }
411 BinOp::GreaterThanOrEquals => {
412 self.builder.push(LT);
413 self.builder.push(ISZERO);
414 }
415 _ => {
416 unreachable!();
417 }
418 }
419 Ok(())
421 }
422
423 fn translate_array_access(&mut self, src: &Term, index: &Term) -> Result {
432 match src {
433 Term::MemoryAccess(r) => self.translate_memory_access(*r, index),
434 _ => Err(CompilerError::InvalidMemoryAccess),
435 }
436 }
437
438 fn translate_memory_access(&mut self, region: Region, index: &Term) -> Result {
439 self.translate(index)?;
441 match region {
443 Region::Memory => {
444 self.builder.push(MLOAD);
445 }
446 Region::Storage => {
447 self.builder.push(SLOAD);
448 }
449 Region::CallData => {
450 self.builder.push(CALLDATALOAD);
451 }
452 }
453 Ok(())
455 }
456
457 fn translate_literal(&mut self, digits: &[u8], radix: u32) -> Result {
462 let val = from_be_digits(digits, radix);
463 self.builder.push(make_push(val)?);
464 Ok(())
465 }
466}
467
468impl TryFrom<&[Term]> for Assembly {
475 type Error = CompilerError;
476
477 fn try_from(terms: &[Term]) -> std::result::Result<Self, Self::Error> {
478 try_from(terms)
479 }
480}
481
482impl<const N: usize> TryFrom<&[Term; N]> for Assembly {
485 type Error = crate::il::CompilerError;
486
487 fn try_from(terms: &[Term; N]) -> std::result::Result<Self, Self::Error> {
488 try_from(terms)
489 }
490}
491
492fn label_bytes(index: usize) -> Vec<u8> {
497 vec![(index / 256) as u8, (index % 256) as u8]
499}
500
501fn try_from(terms: &[Term]) -> std::result::Result<Assembly, CompilerError> {
502 let mut compiler = Compiler::new();
503 for t in terms {
505 compiler.translate(t)?;
506 }
507 Ok(compiler.to_assembly())
509}
510
511fn make_push(val: u128) -> std::result::Result<Instruction, CompilerError> {
513 let bytes = to_be_bytes(val);
514 if bytes.len() > 32 {
516 Err(CompilerError::LiteralOverflow)
518 } else {
519 Ok(PUSH(bytes))
520 }
521}