analyzer.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. use std::{
  2. io::{stdin, stdout, Read, Write},
  3. str::Chars,
  4. };
  5. use super::{
  6. ast::{Arg, Constant, Literal, Statement, StatementType, Var, Variable, Witness},
  7. error::ErrorEmitter,
  8. Opcode, VarType,
  9. };
  10. pub struct Analyzer {
  11. pub constants: Vec<Constant>,
  12. pub witnesses: Vec<Witness>,
  13. pub statements: Vec<Statement>,
  14. pub literals: Vec<Literal>,
  15. pub stack: Vec<Variable>,
  16. error: ErrorEmitter,
  17. }
  18. impl Analyzer {
  19. pub fn new(
  20. filename: &str,
  21. source: Chars,
  22. constants: Vec<Constant>,
  23. witnesses: Vec<Witness>,
  24. statements: Vec<Statement>,
  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: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
  29. let error = ErrorEmitter::new("Semantic", filename, lines);
  30. Self { constants, witnesses, statements, literals: vec![], stack: vec![], error }
  31. }
  32. pub fn analyze_types(&mut self) {
  33. // To work around the pedantic safety, we'll make new vectors and then
  34. // replace the `statements` and `stack` vectors from the `Analyzer`
  35. // object when we are done.
  36. let mut statements = vec![];
  37. let mut stack = vec![];
  38. for statement in &self.statements {
  39. //println!("{:?}", statement);
  40. let mut stmt = statement.clone();
  41. let (return_types, arg_types) = statement.opcode.arg_types();
  42. let mut rhs = vec![];
  43. // This handling is kinda limiting, but it'll do for now.
  44. if !(arg_types[0] == VarType::BaseArray || arg_types[0] == VarType::ScalarArray) {
  45. // Check that number of args is correct
  46. if statement.rhs.len() != arg_types.len() {
  47. self.error.abort(
  48. &format!(
  49. "Incorrect number of arguments for statement. Expected {}, got {}.",
  50. arg_types.len(),
  51. statement.rhs.len()
  52. ),
  53. statement.line,
  54. 1,
  55. );
  56. }
  57. } else {
  58. // In case of arrays, check there's at least one element.
  59. if statement.rhs.is_empty() {
  60. self.error.abort(
  61. "Expected at least one element for statement using arrays.",
  62. statement.line,
  63. 1,
  64. );
  65. }
  66. }
  67. // Edge-cases for some opcodes
  68. #[allow(clippy::single_match)]
  69. match &statement.opcode {
  70. Opcode::RangeCheck => {
  71. if let Arg::Lit(arg0) = &statement.rhs[0] {
  72. if &arg0.name != "64" && &arg0.name != "253" {
  73. self.error.abort(
  74. "Supported range checks are only 64 and 253 bits.",
  75. arg0.line,
  76. arg0.column,
  77. );
  78. }
  79. } else {
  80. self.error.abort(
  81. "Invalid argument for range_check opcode.",
  82. statement.line,
  83. 0,
  84. );
  85. }
  86. }
  87. _ => {}
  88. }
  89. for (idx, arg) in statement.rhs.iter().enumerate() {
  90. // In case an argument is a function call, we will first
  91. // convert it to another statement that will get executed
  92. // before this one. An important assumption is that this
  93. // opcode has a return value. When executed we will push
  94. // this value onto the stack and use it as a reference to
  95. // the actual statement we're parsing at this moment.
  96. // TODO: FIXME: This needs a recursive algorithm, as this
  97. // only allows a single nested function.
  98. if let Arg::Func(func) = arg {
  99. let (f_return_types, f_arg_types) = func.opcode.arg_types();
  100. if f_return_types.is_empty() {
  101. self.error.abort(
  102. &format!(
  103. "Used a function argument which doesn't have a return value: {:?}",
  104. func.opcode
  105. ),
  106. statement.line,
  107. 1,
  108. );
  109. }
  110. let v = Variable {
  111. name: func.lhs.clone().unwrap().name,
  112. typ: f_return_types[0],
  113. line: func.lhs.clone().unwrap().line,
  114. column: func.lhs.clone().unwrap().column,
  115. };
  116. // FIXME: Needs better *Array handling.
  117. if arg_types[0] == VarType::BaseArray {
  118. if f_return_types[0] != VarType::Base {
  119. self.error.abort(
  120. &format!(
  121. "Function passed as argument returns wrong type. Expected `{:?}`, got `{:?}`.",
  122. VarType::Base,
  123. f_return_types[0],
  124. ),
  125. v.line,
  126. v.column,
  127. );
  128. }
  129. } else if arg_types[0] == VarType::ScalarArray {
  130. if f_return_types[0] != VarType::Scalar {
  131. self.error.abort(
  132. &format!(
  133. "Function passed as argument returns wrong type. Expected `{:?}`, got `{:?}`.",
  134. VarType::Scalar,
  135. f_return_types[0],
  136. ),
  137. v.line,
  138. v.column,
  139. );
  140. }
  141. } else if f_return_types[0] != arg_types[idx] {
  142. self.error.abort(
  143. &format!(
  144. "Function passed as argument returns wrong type. Expected `{:?}`, got `{:?}`.",
  145. arg_types[idx],
  146. f_return_types[0],
  147. ),
  148. v.line,
  149. v.column,
  150. );
  151. }
  152. // Replace the statement function call with the variable from
  153. // the statement we just created to represent this nest.
  154. stmt.rhs[idx] = Arg::Var(v.clone());
  155. let mut rhs_inner = vec![];
  156. for (inner_idx, i) in func.rhs.iter().enumerate() {
  157. if let Arg::Var(v) = i {
  158. if let Some(var_ref) = self.lookup_var(&v.name) {
  159. let (var_type, ln, col) = match var_ref {
  160. Var::Constant(c) => (c.typ, c.line, c.column),
  161. Var::Witness(c) => (c.typ, c.line, c.column),
  162. Var::Variable(c) => (c.typ, c.line, c.column),
  163. };
  164. if var_type != f_arg_types[inner_idx] {
  165. self.error.abort(
  166. &format!(
  167. "Incorrect argument type. Expected `{:?}`, got `{:?}`.",
  168. f_arg_types[inner_idx], var_type
  169. ),
  170. ln,
  171. col,
  172. );
  173. }
  174. // Apply the proper type.
  175. let mut v_new = v.clone();
  176. v_new.typ = var_type;
  177. rhs_inner.push(Arg::Var(v_new));
  178. continue
  179. }
  180. self.error.abort(
  181. &format!("Unknown variable reference `{}`.", v.name),
  182. v.line,
  183. v.column,
  184. );
  185. } else {
  186. unimplemented!()
  187. }
  188. }
  189. let s = Statement {
  190. typ: func.typ,
  191. opcode: func.opcode,
  192. lhs: Some(v.clone()),
  193. rhs: rhs_inner,
  194. line: func.line,
  195. };
  196. // The lhs of the inner function call becomes rhs of the outer one.
  197. rhs.push(Arg::Var(v.clone()));
  198. // Add this to the list of statements.
  199. statements.push(s);
  200. // We replace self.stack here so we can do proper stack lookups.
  201. stack.push(v.clone());
  202. self.stack = stack.clone();
  203. //println!("{:#?}", stack);
  204. //println!("{:#?}", statements);
  205. continue
  206. } // <-- Arg::Func
  207. // The literals get pushed on their own "stack", and
  208. // then the compiler will reference them by their own
  209. // index when it comes to running the statement that
  210. // requires the literal type.
  211. if let Arg::Lit(v) = arg {
  212. // Match this literal type to a VarType for
  213. // type checking.
  214. let var_type = v.typ.to_vartype();
  215. if var_type != arg_types[idx] {
  216. self.error.abort(
  217. &format!(
  218. "Incorrect argument type. Expected `{:?}`, got `{:?}`.",
  219. arg_types[idx], var_type
  220. ),
  221. v.line,
  222. v.column,
  223. );
  224. }
  225. self.literals.push(v.clone());
  226. rhs.push(Arg::Lit(v.clone()));
  227. continue
  228. }
  229. if let Arg::Var(v) = arg {
  230. // Look up variable and check if type is correct.
  231. if let Some(s_var) = self.lookup_var(&v.name) {
  232. let (var_type, _ln, _col) = match s_var {
  233. Var::Constant(c) => (c.typ, c.line, c.column),
  234. Var::Witness(c) => (c.typ, c.line, c.column),
  235. Var::Variable(c) => (c.typ, c.line, c.column),
  236. };
  237. // FIXME: Better array handling
  238. if arg_types[0] == VarType::BaseArray {
  239. if var_type != VarType::Base {
  240. self.error.abort(
  241. &format!(
  242. "Incorrect argument type. Expected `{:?}`, got `{:?}`.",
  243. VarType::Base,
  244. var_type
  245. ),
  246. v.line,
  247. v.column,
  248. );
  249. }
  250. } else if arg_types[0] == VarType::ScalarArray {
  251. if var_type != VarType::Scalar {
  252. self.error.abort(
  253. &format!(
  254. "Incorrect argument type. Expected `{:?}`, got `{:?}`.",
  255. VarType::Scalar,
  256. var_type
  257. ),
  258. v.line,
  259. v.column,
  260. );
  261. }
  262. } else if var_type != arg_types[idx] {
  263. self.error.abort(
  264. &format!(
  265. "Incorrect argument type. Expected `{:?}`, got `{:?}`.",
  266. arg_types[idx], var_type
  267. ),
  268. v.line,
  269. v.column,
  270. );
  271. }
  272. // Replace Dummy type with correct type.
  273. let mut v_new = v.clone();
  274. v_new.typ = var_type;
  275. rhs.push(Arg::Var(v_new));
  276. continue
  277. }
  278. self.error.abort(
  279. &format!("Unknown variable reference `{}`.", v.name),
  280. v.line,
  281. v.column,
  282. );
  283. }
  284. } // <-- statement.rhs.iter().enumerate()
  285. // We now type-checked and assigned types to the statement rhs,
  286. // so now we apply it to the statement.
  287. stmt.rhs = rhs;
  288. // In case this statement is an assignment, we will push its
  289. // result on the stack.
  290. if statement.typ == StatementType::Assign {
  291. let mut var = statement.lhs.clone().unwrap();
  292. var.typ = return_types[0];
  293. stmt.lhs = Some(var.clone());
  294. stack.push(var.clone());
  295. self.stack = stack.clone();
  296. }
  297. //println!("{:#?}", stmt);
  298. statements.push(stmt);
  299. } // <-- for statement in &self.statements
  300. // Here we replace the self.statements and self.stack with what we
  301. // built so far. These can be used later on by the compiler after
  302. // this function is finished.
  303. self.statements = statements;
  304. self.stack = stack;
  305. //println!("=================STATEMENTS===============\n{:#?}", self.statements);
  306. //println!("===================STACK==================\n{:#?}", self.stack);
  307. //println!("==================LITERALS================\n{:#?}", self.literals);
  308. }
  309. fn lookup_var(&self, name: &str) -> Option<Var> {
  310. if let Some(r) = self.lookup_constant(name) {
  311. return Some(Var::Constant(r))
  312. }
  313. if let Some(r) = self.lookup_witness(name) {
  314. return Some(Var::Witness(r))
  315. }
  316. if let Some(r) = self.lookup_stack(name) {
  317. return Some(Var::Variable(r))
  318. }
  319. None
  320. }
  321. fn lookup_constant(&self, name: &str) -> Option<Constant> {
  322. for i in &self.constants {
  323. if i.name == name {
  324. return Some(i.clone())
  325. }
  326. }
  327. None
  328. }
  329. fn lookup_witness(&self, name: &str) -> Option<Witness> {
  330. for i in &self.witnesses {
  331. if i.name == name {
  332. return Some(i.clone())
  333. }
  334. }
  335. None
  336. }
  337. fn lookup_stack(&self, name: &str) -> Option<Variable> {
  338. for i in &self.stack {
  339. if i.name == name {
  340. return Some(i.clone())
  341. }
  342. }
  343. None
  344. }
  345. pub fn analyze_semantic(&mut self) {
  346. let mut stack = vec![];
  347. println!("Loading constants...\n-----");
  348. for i in &self.constants {
  349. println!("Adding `{}` to stack", i.name);
  350. stack.push(&i.name);
  351. Analyzer::pause();
  352. }
  353. println!("Stack:\n{:#?}\n-----", stack);
  354. println!("Loading witnesses...\n-----");
  355. for i in &self.witnesses {
  356. println!("Adding `{}` to stack", i.name);
  357. stack.push(&i.name);
  358. Analyzer::pause();
  359. }
  360. println!("Stack:\n{:#?}\n-----", stack);
  361. println!("Loading circuit...");
  362. for i in &self.statements {
  363. let mut argnames = vec![];
  364. for arg in &i.rhs {
  365. if let Arg::Var(arg) = arg {
  366. argnames.push(arg.name.clone());
  367. } else if let Arg::Lit(lit) = arg {
  368. argnames.push(lit.name.clone());
  369. } else {
  370. unreachable!()
  371. }
  372. }
  373. println!("Executing: {:?}({:?})", i.opcode, argnames);
  374. Analyzer::pause();
  375. for arg in &i.rhs {
  376. if let Arg::Var(arg) = arg {
  377. print!("Looking up `{}` on the stack... ", arg.name);
  378. if let Some(index) = stack.iter().position(|&r| r == &arg.name) {
  379. println!("Found at stack index {}", index);
  380. } else {
  381. self.error.abort(
  382. &format!("Could not find `{}` on the stack", arg.name),
  383. arg.line,
  384. arg.column,
  385. );
  386. }
  387. } else if let Arg::Lit(lit) = arg {
  388. println!("Using literal `{}`", lit.name);
  389. } else {
  390. println!("{:#?}", arg);
  391. unreachable!();
  392. }
  393. Analyzer::pause();
  394. }
  395. match i.typ {
  396. StatementType::Assign => {
  397. println!("Pushing result as `{}` to stack", &i.lhs.as_ref().unwrap().name);
  398. stack.push(&i.lhs.as_ref().unwrap().name);
  399. println!("Stack:\n{:#?}\n-----", stack);
  400. }
  401. StatementType::Call => {
  402. println!("-----");
  403. }
  404. _ => unreachable!(),
  405. }
  406. }
  407. }
  408. fn pause() {
  409. let msg = b"[Press Enter to continue]\r";
  410. let mut stdout = stdout();
  411. let _ = stdout.write(msg).unwrap();
  412. stdout.flush().unwrap();
  413. let _ = stdin().read(&mut [0]).unwrap();
  414. write!(stdout, "{}{}\r", termion::cursor::Up(1), termion::clear::CurrentLine).unwrap();
  415. }
  416. }