compiler.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. use std::{io, io::Write, process, str::Chars};
  2. use darkfi::util::serial::{serialize, VarInt};
  3. use termion::{color, style};
  4. use crate::ast::{Constants, StatementType, Statements, Witnesses};
  5. /// Version of the binary
  6. pub const BINARY_VERSION: u8 = 1;
  7. /// Magic bytes prepended to the binary
  8. pub const MAGIC_BYTES: [u8; 4] = [0x0b, 0x00, 0xb1, 0x35];
  9. pub struct Compiler {
  10. file: String,
  11. lines: Vec<String>,
  12. constants: Constants,
  13. witnesses: Witnesses,
  14. statements: Statements,
  15. debug_info: bool,
  16. }
  17. impl Compiler {
  18. pub fn new(
  19. filename: &str,
  20. source: Chars,
  21. constants: Constants,
  22. witnesses: Witnesses,
  23. statements: Statements,
  24. debug_info: bool,
  25. ) -> Self {
  26. // For nice error reporting, we'll load everything into a string
  27. // vector so we have references to lines.
  28. let lines = source.as_str().lines().map(|x| x.to_string()).collect();
  29. Compiler { file: filename.to_string(), lines, constants, witnesses, statements, debug_info }
  30. }
  31. pub fn compile(&self) -> Vec<u8> {
  32. let mut bincode = vec![];
  33. // Write the magic bytes and version
  34. bincode.extend_from_slice(&MAGIC_BYTES);
  35. bincode.push(BINARY_VERSION);
  36. let mut stack_idx: u64 = 0;
  37. // Temporary stack vector for lookups
  38. let mut tmp_stack = vec![];
  39. bincode.extend_from_slice(b".constant");
  40. for i in &self.constants {
  41. tmp_stack.push(i.name.as_str());
  42. bincode.push(i.typ as u8);
  43. bincode.extend_from_slice(&serialize(&i.name));
  44. stack_idx += 1;
  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. stack_idx += 1;
  51. }
  52. bincode.extend_from_slice(b".circuit");
  53. for i in &self.statements {
  54. match i.typ {
  55. StatementType::Assignment => {
  56. tmp_stack.push(&i.variable.as_ref().unwrap().name);
  57. stack_idx += 1;
  58. }
  59. // In case of a simple call, we don't append anything to the stack
  60. StatementType::Call => {}
  61. _ => unreachable!(),
  62. }
  63. bincode.push(i.opcode as u8);
  64. bincode.extend_from_slice(&serialize(&VarInt(i.args.len() as u64)));
  65. for arg in &i.args {
  66. if let Some(found) = Compiler::lookup_stack(&tmp_stack, &arg.name) {
  67. bincode.extend_from_slice(&serialize(&VarInt(found)));
  68. continue
  69. }
  70. self.error(
  71. format!("Failed finding a stack reference for `{}`", arg.name),
  72. arg.line,
  73. arg.column,
  74. );
  75. }
  76. }
  77. // If we're not doing debug info, we're done here and can return.
  78. if !self.debug_info {
  79. return bincode
  80. }
  81. // TODO: Otherwise, we proceed appending debug info
  82. bincode
  83. }
  84. fn lookup_stack(stack: &[&str], name: &str) -> Option<u64> {
  85. for (idx, n) in stack.iter().enumerate() {
  86. if n == &name {
  87. return Some(idx.try_into().unwrap())
  88. }
  89. }
  90. None
  91. }
  92. fn error(&self, msg: String, ln: usize, col: usize) {
  93. let err_msg = format!("{} (line {}, column {})", msg, ln, col);
  94. let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
  95. let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
  96. let caret = format!("{:width$}^", "", width = pad);
  97. let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
  98. Compiler::abort(&msg);
  99. }
  100. fn abort(msg: &str) {
  101. let stderr = io::stderr();
  102. let mut handle = stderr.lock();
  103. write!(
  104. handle,
  105. "{}{}Compiler error:{} {}",
  106. style::Bold,
  107. color::Fg(color::Red),
  108. style::Reset,
  109. msg,
  110. )
  111. .unwrap();
  112. handle.flush().unwrap();
  113. process::exit(1);
  114. }
  115. }