analyzer.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. use std::{io, io::Write, process, str::Chars};
  2. use termion::{color, style};
  3. use crate::{
  4. ast::{
  5. Constant, Constants, StatementType, Statements, Var, Variable, Variables, Witness,
  6. Witnesses,
  7. },
  8. types::Type,
  9. };
  10. pub struct Analyzer {
  11. file: String,
  12. lines: Vec<String>,
  13. pub constants: Constants,
  14. pub witnesses: Witnesses,
  15. pub statements: Statements,
  16. pub stack: Variables,
  17. }
  18. impl Analyzer {
  19. pub fn new(
  20. filename: &str,
  21. source: Chars,
  22. constants: Constants,
  23. witnesses: Witnesses,
  24. statements: Statements,
  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. Analyzer {
  30. file: filename.to_string(),
  31. lines,
  32. constants,
  33. witnesses,
  34. statements,
  35. stack: vec![],
  36. }
  37. }
  38. pub fn analyze_types(&mut self) {
  39. // To work around the pedantic safety, we'll make new vectors and
  40. // then replace the `statements` and `stack` vectors from the
  41. // Analyzer object when we're done.
  42. let mut statements = vec![];
  43. let mut stack = vec![];
  44. for statement in &self.statements {
  45. let mut stmt = statement.clone();
  46. match statement.typ {
  47. StatementType::Assignment => {
  48. let (return_types, arg_types) = statement.opcode.arg_types();
  49. let mut args = vec![];
  50. // For variable length args, we implement BaseArray.
  51. // It's kinda ugly.
  52. if arg_types[0] == Type::BaseArray {
  53. for i in &statement.args {
  54. if let Some(v) = self.lookup_var(&i.name) {
  55. let var_type = match v {
  56. Var::Constant(c) => c.typ,
  57. Var::Witness(c) => c.typ,
  58. Var::Variable(c) => c.typ,
  59. };
  60. if var_type != Type::Base {
  61. self.error(
  62. format!(
  63. "Incorrect argument type. Expected `{:?}`, got `{:?}`",
  64. Type::Base,
  65. var_type
  66. ),
  67. i.line,
  68. i.column,
  69. );
  70. }
  71. let mut arg = i.clone();
  72. arg.typ = var_type;
  73. args.push(arg);
  74. } else {
  75. self.error(
  76. format!("Unknown argument reference `{}`.", i.name),
  77. i.line,
  78. i.column,
  79. );
  80. }
  81. }
  82. } else {
  83. for (idx, i) in statement.args.iter().enumerate() {
  84. if let Some(v) = self.lookup_var(&i.name) {
  85. let var_type = match v {
  86. Var::Constant(c) => c.typ,
  87. Var::Witness(c) => c.typ,
  88. Var::Variable(c) => c.typ,
  89. };
  90. if var_type != arg_types[idx] {
  91. self.error(
  92. format!(
  93. "Incorrect argument type. Expected `{:?}`, got `{:?}`",
  94. arg_types[idx], var_type,
  95. ),
  96. i.line,
  97. i.column,
  98. );
  99. }
  100. let mut arg = i.clone();
  101. arg.typ = var_type;
  102. args.push(arg);
  103. } else {
  104. self.error(
  105. format!("Unknown argument reference `{}`.", i.name),
  106. i.line,
  107. i.column,
  108. );
  109. }
  110. }
  111. }
  112. // Currently we just support a single return type.
  113. let mut var = statement.variable.clone().unwrap();
  114. var.typ = return_types[0];
  115. stmt.variable = Some(var.clone());
  116. stack.push(var.clone());
  117. self.stack = stack.clone();
  118. stmt.args = args;
  119. statements.push(stmt);
  120. }
  121. StatementType::Call => {
  122. let (_, arg_types) = statement.opcode.arg_types();
  123. let mut args = vec![];
  124. // For variable length args, we implement BaseArray.
  125. // It's kinda ugly.
  126. if arg_types[0] == Type::BaseArray {
  127. for i in &statement.args {
  128. if let Some(v) = self.lookup_var(&i.name) {
  129. let var_type = match v {
  130. Var::Constant(c) => c.typ,
  131. Var::Witness(c) => c.typ,
  132. Var::Variable(c) => c.typ,
  133. };
  134. if var_type != Type::Base {
  135. self.error(
  136. format!(
  137. "Incorrect argument type. Expected `{:?}`, got `{:?}`",
  138. Type::Base,
  139. var_type
  140. ),
  141. i.line,
  142. i.column,
  143. );
  144. }
  145. let mut arg = i.clone();
  146. arg.typ = var_type;
  147. args.push(arg);
  148. } else {
  149. self.error(
  150. format!("Unknown argument reference `{}`.", i.name),
  151. i.line,
  152. i.column,
  153. );
  154. }
  155. }
  156. } else {
  157. for (idx, i) in statement.args.iter().enumerate() {
  158. if let Some(v) = self.lookup_var(&i.name) {
  159. let var_type = match v {
  160. Var::Constant(c) => c.typ,
  161. Var::Witness(c) => c.typ,
  162. Var::Variable(c) => c.typ,
  163. };
  164. if var_type != arg_types[idx] {
  165. self.error(
  166. format!(
  167. "Incorrect argument type. Expected `{:?}`, got `{:?}`",
  168. arg_types[idx], var_type,
  169. ),
  170. i.line,
  171. i.column,
  172. );
  173. }
  174. let mut arg = i.clone();
  175. arg.typ = var_type;
  176. args.push(arg);
  177. } else {
  178. self.error(
  179. format!("Unknown argument reference `{}`.", i.name),
  180. i.line,
  181. i.column,
  182. );
  183. }
  184. }
  185. }
  186. stmt.args = args;
  187. statements.push(stmt);
  188. }
  189. StatementType::Noop => unreachable!(),
  190. }
  191. }
  192. self.statements = statements;
  193. }
  194. pub fn analyze_semantic(&mut self) {
  195. // println!("{:#?}", self.constants);
  196. // println!("{:#?}", self.witnesses);
  197. // println!("{:#?}", self.statements);
  198. }
  199. fn lookup_var(&self, name: &str) -> Option<Var> {
  200. if let Some(r) = self.lookup_constant(name) {
  201. return Some(Var::Constant(r))
  202. }
  203. if let Some(r) = self.lookup_witness(name) {
  204. return Some(Var::Witness(r))
  205. }
  206. if let Some(r) = self.lookup_stack(name) {
  207. return Some(Var::Variable(r))
  208. }
  209. None
  210. }
  211. fn lookup_constant(&self, name: &str) -> Option<Constant> {
  212. for i in &self.constants {
  213. if i.name == name {
  214. return Some(i.clone())
  215. }
  216. }
  217. None
  218. }
  219. fn lookup_witness(&self, name: &str) -> Option<Witness> {
  220. for i in &self.witnesses {
  221. if i.name == name {
  222. return Some(i.clone())
  223. }
  224. }
  225. None
  226. }
  227. fn lookup_stack(&self, name: &str) -> Option<Variable> {
  228. for i in &self.stack {
  229. if i.name == name {
  230. return Some(i.clone())
  231. }
  232. }
  233. None
  234. }
  235. fn error(&self, msg: String, ln: usize, col: usize) {
  236. let err_msg = format!("{} (line {}, column {})", msg, ln, col);
  237. let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
  238. let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
  239. let caret = format!("{:width$}^", "", width = pad);
  240. let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
  241. Analyzer::abort(&msg);
  242. }
  243. fn abort(msg: &str) {
  244. let stderr = io::stderr();
  245. let mut handle = stderr.lock();
  246. write!(
  247. handle,
  248. "{}{}Semantic error:{} {}",
  249. style::Bold,
  250. color::Fg(color::Red),
  251. style::Reset,
  252. msg,
  253. )
  254. .unwrap();
  255. handle.flush().unwrap();
  256. process::exit(1);
  257. }
  258. }