compiler.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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(&VarInt(stack_idx)));
  44. bincode.extend_from_slice(i.name.as_bytes());
  45. stack_idx += 1;
  46. }
  47. bincode.extend_from_slice(b".contract");
  48. for i in &self.witnesses {
  49. tmp_stack.push(i.name.as_str());
  50. bincode.push(i.typ as u8);
  51. stack_idx += 1;
  52. }
  53. bincode.extend_from_slice(b".circuit");
  54. for i in &self.statements {
  55. match i.typ {
  56. StatementType::Assignment => {
  57. tmp_stack.push(&i.variable.as_ref().unwrap().name);
  58. stack_idx += 1;
  59. }
  60. // In case of a simple call, we don't append anything to the stack
  61. StatementType::Call => {}
  62. _ => unreachable!(),
  63. }
  64. bincode.push(i.opcode as u8);
  65. bincode.extend_from_slice(&serialize(&VarInt(i.args.len() as u64)));
  66. for arg in &i.args {
  67. if let Some(found) = Compiler::lookup_stack(&tmp_stack, &arg.name) {
  68. bincode.extend_from_slice(&serialize(&VarInt(found)));
  69. continue
  70. }
  71. self.error(
  72. format!("Failed finding a stack reference for `{}`", arg.name),
  73. arg.line,
  74. arg.column,
  75. );
  76. }
  77. }
  78. // If we're not doing debug info, we're done here and can return.
  79. if !self.debug_info {
  80. return bincode
  81. }
  82. // TODO: Otherwise, we proceed appending debug info
  83. bincode
  84. }
  85. fn lookup_stack(stack: &[&str], name: &str) -> Option<u64> {
  86. for (idx, n) in stack.iter().enumerate() {
  87. if n == &name {
  88. return Some(idx.try_into().unwrap())
  89. }
  90. }
  91. None
  92. }
  93. fn error(&self, msg: String, ln: usize, col: usize) {
  94. let err_msg = format!("{} (line {}, column {})", msg, ln, col);
  95. let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
  96. let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
  97. let caret = format!("{:width$}^", "", width = pad);
  98. let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
  99. Compiler::abort(&msg);
  100. }
  101. fn abort(msg: &str) {
  102. let stderr = io::stderr();
  103. let mut handle = stderr.lock();
  104. write!(
  105. handle,
  106. "{}{}Compiler error:{} {}",
  107. style::Bold,
  108. color::Fg(color::Red),
  109. style::Reset,
  110. msg,
  111. )
  112. .unwrap();
  113. handle.flush().unwrap();
  114. process::exit(1);
  115. }
  116. }