analyzer.rs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. use std::{
  2. io::{stdin, stdout, Read, Write},
  3. str::Chars,
  4. };
  5. use super::{
  6. ast::{
  7. Constant, Constants, StatementType, Statements, Var, Variable, Variables, Witness,
  8. Witnesses,
  9. },
  10. error::ErrorEmitter,
  11. types::Type,
  12. };
  13. pub struct Analyzer {
  14. pub constants: Constants,
  15. pub witnesses: Witnesses,
  16. pub statements: Statements,
  17. pub stack: Variables,
  18. error: ErrorEmitter,
  19. }
  20. impl Analyzer {
  21. pub fn new(
  22. filename: &str,
  23. source: Chars,
  24. constants: Constants,
  25. witnesses: Witnesses,
  26. statements: Statements,
  27. ) -> Self {
  28. // For nice error reporting, we'll load everything into a string
  29. // vector so we have references to lines.
  30. let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
  31. let error = ErrorEmitter::new("Semantic", filename, lines.clone());
  32. Analyzer { constants, witnesses, statements, stack: vec![], error }
  33. }
  34. pub fn analyze_types(&mut self) {
  35. // To work around the pedantic safety, we'll make new vectors and
  36. // then replace the `statements` and `stack` vectors from the
  37. // `Analyzer` object when we're done.
  38. let mut statements = vec![];
  39. let mut stack = vec![];
  40. for statement in &self.statements {
  41. let mut stmt = statement.clone();
  42. let (return_types, arg_types) = statement.opcode.arg_types();
  43. let mut args = vec![];
  44. // For variable length args, we implement `BaseArray` and `ScalarArray`.
  45. // It's kinda ugly.
  46. if arg_types[0] == Type::BaseArray || arg_types[0] == Type::ScalarArray {
  47. if statement.args.is_empty() {
  48. self.error.emit(
  49. format!(
  50. "Passed no arguments to `{:?}` call. Expected at least 1.",
  51. statement.opcode
  52. ),
  53. statement.line,
  54. 1,
  55. );
  56. }
  57. for i in &statement.args {
  58. if let Some(v) = self.lookup_var(&i.name) {
  59. let var_type = match v {
  60. Var::Constant(c) => c.typ,
  61. Var::Witness(c) => c.typ,
  62. Var::Variable(c) => c.typ,
  63. };
  64. if arg_types[0] == Type::BaseArray && var_type != Type::Base {
  65. self.error.emit(
  66. format!(
  67. "Incorrect argument type. Expected `{:?}`, got `{:?}`",
  68. arg_types[0],
  69. Type::Base,
  70. ),
  71. i.line,
  72. i.column,
  73. );
  74. }
  75. if arg_types[0] == Type::ScalarArray && var_type != Type::Scalar {
  76. self.error.emit(
  77. format!(
  78. "Incorrect argument type. Expected `{:?}`, got `{:?}`",
  79. arg_types[0],
  80. Type::Scalar,
  81. ),
  82. i.line,
  83. i.column,
  84. );
  85. }
  86. let mut arg = i.clone();
  87. arg.typ = var_type;
  88. args.push(arg);
  89. } else {
  90. self.error.emit(
  91. format!("Unknown argument reference `{}`.", i.name),
  92. i.line,
  93. i.column,
  94. );
  95. }
  96. }
  97. } else {
  98. if statement.args.len() != arg_types.len() {
  99. self.error.emit(
  100. format!(
  101. "Incorrent number of args to `{:?}` call. Expected {}, got {}",
  102. statement.opcode,
  103. arg_types.len(),
  104. statement.args.len()
  105. ),
  106. statement.line,
  107. 1,
  108. );
  109. }
  110. for (idx, i) in statement.args.iter().enumerate() {
  111. if let Some(v) = self.lookup_var(&i.name) {
  112. let var_type = match v {
  113. Var::Constant(c) => c.typ,
  114. Var::Witness(c) => c.typ,
  115. Var::Variable(c) => c.typ,
  116. };
  117. if var_type != arg_types[idx] {
  118. self.error.emit(
  119. format!(
  120. "Incorrect argument type. Expected `{:?}`, got `{:?}`",
  121. arg_types[idx], var_type,
  122. ),
  123. i.line,
  124. i.column,
  125. );
  126. }
  127. let mut arg = i.clone();
  128. arg.typ = var_type;
  129. args.push(arg);
  130. } else {
  131. self.error.emit(
  132. format!("Unknown argument reference `{}`.", i.name),
  133. i.line,
  134. i.column,
  135. );
  136. }
  137. }
  138. }
  139. match statement.typ {
  140. StatementType::Assignment => {
  141. // Currently we just support a single return type.
  142. let mut var = statement.variable.clone().unwrap();
  143. var.typ = return_types[0];
  144. stmt.variable = Some(var.clone());
  145. stack.push(var.clone());
  146. self.stack = stack.clone();
  147. stmt.args = args;
  148. statements.push(stmt);
  149. }
  150. StatementType::Call => {
  151. stmt.args = args;
  152. statements.push(stmt);
  153. }
  154. _ => unreachable!(),
  155. }
  156. }
  157. self.statements = statements;
  158. }
  159. pub fn analyze_semantic(&mut self) {
  160. let mut stack = vec![];
  161. println!("Loading constants...\n-----");
  162. for i in &self.constants {
  163. println!("Adding `{}` to stack", i.name);
  164. stack.push(&i.name);
  165. Analyzer::pause();
  166. }
  167. println!("Stack:\n{:#?}\n-----", stack);
  168. println!("Loading witnesses...\n-----");
  169. for i in &self.witnesses {
  170. println!("Adding `{}` to stack", i.name);
  171. stack.push(&i.name);
  172. Analyzer::pause();
  173. }
  174. println!("Stack:\n{:#?}\n-----", stack);
  175. println!("Loading circuit...");
  176. for i in &self.statements {
  177. let argnames: Vec<String> = i.args.iter().map(|x| x.name.clone()).collect();
  178. println!("Executing: {:?}({:?})", i.opcode, argnames);
  179. Analyzer::pause();
  180. for arg in &i.args {
  181. print!("Looking up `{}` on the stack... ", arg.name);
  182. if let Some(index) = stack.iter().position(|&r| r == &arg.name) {
  183. println!("Found at stack index {}", index);
  184. } else {
  185. self.error.emit(
  186. format!("Could not find `{}` on the stack", arg.name),
  187. arg.line,
  188. arg.column,
  189. );
  190. }
  191. Analyzer::pause();
  192. }
  193. match i.typ {
  194. StatementType::Assignment => {
  195. println!("Pushing result as `{}` to stack", &i.variable.as_ref().unwrap().name);
  196. stack.push(&i.variable.as_ref().unwrap().name);
  197. println!("Stack:\n{:#?}\n-----", stack);
  198. }
  199. StatementType::Call => {
  200. println!("-----");
  201. }
  202. _ => unreachable!(),
  203. }
  204. }
  205. // println!("{:#?}", self.constants);
  206. // println!("{:#?}", self.witnesses);
  207. // println!("{:#?}", self.statements);
  208. }
  209. fn lookup_var(&self, name: &str) -> Option<Var> {
  210. if let Some(r) = self.lookup_constant(name) {
  211. return Some(Var::Constant(r))
  212. }
  213. if let Some(r) = self.lookup_witness(name) {
  214. return Some(Var::Witness(r))
  215. }
  216. if let Some(r) = self.lookup_stack(name) {
  217. return Some(Var::Variable(r))
  218. }
  219. None
  220. }
  221. fn lookup_constant(&self, name: &str) -> Option<Constant> {
  222. for i in &self.constants {
  223. if i.name == name {
  224. return Some(i.clone())
  225. }
  226. }
  227. None
  228. }
  229. fn lookup_witness(&self, name: &str) -> Option<Witness> {
  230. for i in &self.witnesses {
  231. if i.name == name {
  232. return Some(i.clone())
  233. }
  234. }
  235. None
  236. }
  237. fn lookup_stack(&self, name: &str) -> Option<Variable> {
  238. for i in &self.stack {
  239. if i.name == name {
  240. return Some(i.clone())
  241. }
  242. }
  243. None
  244. }
  245. fn pause() {
  246. let msg = b"[Press Enter to continue]\r";
  247. let mut stdout = stdout();
  248. let _ = stdout.write(msg).unwrap();
  249. stdout.flush().unwrap();
  250. let _ = stdin().read(&mut [0]).unwrap();
  251. write!(stdout, "{}{}\r", termion::cursor::Up(1), termion::clear::CurrentLine).unwrap();
  252. }
  253. }