compiler.rs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. use std::str::Chars;
  2. use super::{
  3. ast::{Constants, StatementType, Statements, Witnesses},
  4. error::ErrorEmitter,
  5. };
  6. use crate::util::serial::{serialize, VarInt};
  7. /// Version of the binary
  8. pub const BINARY_VERSION: u8 = 1;
  9. /// Magic bytes prepended to the binary
  10. pub const MAGIC_BYTES: [u8; 4] = [0x0b, 0x00, 0xb1, 0x35];
  11. pub struct Compiler {
  12. constants: Constants,
  13. witnesses: Witnesses,
  14. statements: Statements,
  15. debug_info: bool,
  16. error: ErrorEmitter,
  17. }
  18. impl Compiler {
  19. pub fn new(
  20. filename: &str,
  21. source: Chars,
  22. constants: Constants,
  23. witnesses: Witnesses,
  24. statements: Statements,
  25. debug_info: bool,
  26. ) -> Self {
  27. // For nice error reporting, we'll load everything into a string
  28. // vector so we have references to lines.
  29. let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
  30. let error = ErrorEmitter::new("Compiler", filename, lines);
  31. Compiler { constants, witnesses, statements, debug_info, error }
  32. }
  33. pub fn compile(&self) -> Vec<u8> {
  34. let mut bincode = vec![];
  35. // Write the magic bytes and version
  36. bincode.extend_from_slice(&MAGIC_BYTES);
  37. bincode.push(BINARY_VERSION);
  38. // Temporary stack vector for lookups
  39. let mut tmp_stack = vec![];
  40. bincode.extend_from_slice(b".constant");
  41. for i in &self.constants {
  42. tmp_stack.push(i.name.as_str());
  43. bincode.push(i.typ as u8);
  44. bincode.extend_from_slice(&serialize(&i.name));
  45. }
  46. bincode.extend_from_slice(b".contract");
  47. for i in &self.witnesses {
  48. tmp_stack.push(i.name.as_str());
  49. bincode.push(i.typ as u8);
  50. }
  51. bincode.extend_from_slice(b".circuit");
  52. for i in &self.statements {
  53. match i.typ {
  54. StatementType::Assignment => {
  55. tmp_stack.push(&i.variable.as_ref().unwrap().name);
  56. }
  57. // In case of a simple call, we don't append anything to the stack
  58. StatementType::Call => {}
  59. _ => unreachable!(),
  60. }
  61. bincode.push(i.opcode as u8);
  62. bincode.extend_from_slice(&serialize(&VarInt(i.args.len() as u64)));
  63. for arg in &i.args {
  64. if let Some(found) = Compiler::lookup_stack(&tmp_stack, &arg.name) {
  65. bincode.extend_from_slice(&serialize(&VarInt(found as u64)));
  66. continue
  67. }
  68. self.error.emit(
  69. format!("Failed finding a stack reference for `{}`", arg.name),
  70. arg.line,
  71. arg.column,
  72. );
  73. }
  74. }
  75. // If we're not doing debug info, we're done here and can return.
  76. if !self.debug_info {
  77. return bincode
  78. }
  79. // TODO: Otherwise, we proceed appending debug info
  80. bincode
  81. }
  82. fn lookup_stack(stack: &[&str], name: &str) -> Option<usize> {
  83. for (idx, n) in stack.iter().enumerate() {
  84. if n == &name {
  85. return Some(idx)
  86. }
  87. }
  88. None
  89. }
  90. }