Przeglądaj źródła

zkas: Add circuit parser skeleton and improve some error handling.

parazyd 4 lat temu
rodzic
commit
6b148dcceb
4 zmienionych plików z 98 dodań i 32 usunięć
  1. 3 3
      zkas/src/bin/zkas.rs
  2. 1 0
      zkas/src/opcode.rs
  3. 93 29
      zkas/src/parser.rs
  4. 1 0
      zkas/src/types.rs

+ 3 - 3
zkas/src/bin/zkas.rs

@@ -21,9 +21,9 @@ fn main() -> Result<()> {
     let parser = Parser::new(filename, source.chars(), tokens);
     let (constants, witnesses, circuit) = parser.parse();
 
-    println!("{:#?}", constants);
-    println!("{:#?}", witnesses);
-    println!("{:#?}", circuit);
+    // println!("{:#?}", constants);
+    // println!("{:#?}", witnesses);
+    // println!("{:#?}", circuit);
 
     Ok(())
 }

+ 1 - 0
zkas/src/opcode.rs

@@ -1,3 +1,4 @@
+// Opcodes supported by the VM
 pub enum OpCode {
     EcAdd = 0x00,
     EcMul = 0x01,

+ 93 - 29
zkas/src/parser.rs

@@ -39,6 +39,10 @@ impl Parser {
         let mut constant_tokens = vec![];
         let mut contract_tokens = vec![];
         let mut circuit_tokens = vec![];
+        // Single statement in the circuit
+        let mut circuit_statement = vec![];
+        // All the circuit statements
+        let mut circuit_statements = vec![];
 
         let mut ast = HashMap::new();
         let mut namespace = String::new();
@@ -207,6 +211,41 @@ impl Parser {
             }
 
             if declaring_circuit {
+                self.check_section_structure("circuit", contract_tokens.clone());
+
+                if circuit_tokens[circuit_tokens.len() - 2].token_type != TokenType::Semicolon {
+                    self.error(
+                        "Circuit section does not end with a semicolon. Would never finish parsing.".to_string(),
+                        circuit_tokens[circuit_tokens.len()-2].line,
+                        circuit_tokens[circuit_tokens.len()-2].column
+                    );
+                }
+
+                // TODO: Do we need this?
+                if namespace_found && namespace != circuit_tokens[0].token {
+                    self.error(
+                        format!(
+                            "Found `{}` namespace. Expected `{}`.",
+                            circuit_tokens[0].token, namespace
+                        ),
+                        circuit_tokens[0].line,
+                        circuit_tokens[0].column,
+                    );
+                } else {
+                    namespace = circuit_tokens[0].token.clone();
+                    namespace_found = true;
+                }
+
+                for i in circuit_tokens.clone() {
+                    if i.token_type == TokenType::Semicolon {
+                        circuit_statements.push(circuit_statement.clone());
+                        // println!("{:?}", circuit_statement);
+                        circuit_statement = vec![];
+                        continue
+                    }
+                    circuit_statement.push(i);
+                }
+
                 declaring_circuit = false;
             }
         }
@@ -215,22 +254,16 @@ impl Parser {
         self.verify_initial_ast(&ast);
 
         // Clean up the `constant` section
-        let (constants, err) =
-            Parser::parse_ast_constants(ast.get(&namespace).unwrap().get("constant").unwrap());
-        if let Some(err_msg) = err {
-            // TODO: Return problematic token from parse_ast_constants()
-            self.error(err_msg, 1, 1);
-        }
+        let c = ast.get(&namespace).unwrap().get("constant").unwrap();
+        let constants = self.parse_ast_constants(c);
 
-        // Clean up the `contract section
-        let (contract, err) =
-            Parser::parse_ast_contract(ast.get(&namespace).unwrap().get("contract").unwrap());
-        if let Some(err_msg) = err {
-            // TODO: Return problematic token from parse_ast_contract()
-            self.error(err_msg, 1, 1);
-        }
+        // Clean up the `contract` section
+        let c = ast.get(&namespace).unwrap().get("contract").unwrap();
+        let contract = self.parse_ast_contract(c);
+
+        // Clean up the `circuit` section
+        // TODO
 
-        // Return
         (constants, contract, HashMap::new())
     }
 
@@ -284,7 +317,9 @@ impl Parser {
             );
         }
 
-        if tokens[2..tokens.len() - 1].len() % 3 != 0 {
+        if section == "constant" ||
+            section == "contract" && tokens[2..tokens.len() - 1].len() % 3 != 0
+        {
             self.error(
                 format!(
                     "Invalid number of elements in `{}` section. Must be pairs of `type:name` separated with a comma `,`",
@@ -296,20 +331,32 @@ impl Parser {
         }
     }
 
-    fn parse_ast_constants(ast: &UnparsedConstants) -> (Constants, Option<String>) {
+    fn parse_ast_constants(&self, ast: &UnparsedConstants) -> Constants {
         let mut ret = vec![];
 
         for (k, v) in ast {
             if &v.0.token != k {
-                return (vec![], Some("Constant name doesn't match token".to_string()))
+                self.error(
+                    format!("Constant name `{}` doesn't match token `{}`.", v.0.token, k),
+                    v.0.line,
+                    v.0.column,
+                );
             }
 
             if v.0.token_type != TokenType::Symbol {
-                return (vec![], Some("Constant name is not a symbol".to_string()))
+                self.error(
+                    format!("Constant name `{}` is not a symbol.", v.0.token),
+                    v.0.line,
+                    v.0.column,
+                );
             }
 
             if v.1.token_type != TokenType::Symbol {
-                return (vec![], Some("Constant type is not a symbol".to_string()))
+                self.error(
+                    format!("Constant type `{}` is not a symbol.", v.1.token),
+                    v.1.line,
+                    v.1.column,
+                );
             }
 
             match v.1.token.as_str() {
@@ -323,29 +370,44 @@ impl Parser {
                 }
 
                 x => {
-                    let err_msg = format!("`{}` is an illegal constant type", x);
-                    return (vec![], Some(err_msg))
+                    self.error(
+                        format!("`{}` is an illegal constant type", x),
+                        v.1.line,
+                        v.1.column,
+                    );
                 }
             }
         }
 
-        (ret, None)
+        ret
     }
 
-    fn parse_ast_contract(ast: &UnparsedWitnesses) -> (Witnesses, Option<String>) {
+    fn parse_ast_contract(&self, ast: &UnparsedWitnesses) -> Witnesses {
         let mut ret = vec![];
 
         for (k, v) in ast {
             if &v.0.token != k {
-                return (vec![], Some("Contract input name doesn't match token".to_string()))
+                self.error(
+                    format!("Witness name `{}` doesn't match token `{}`.", v.0.token, k),
+                    v.0.line,
+                    v.0.column,
+                );
             }
 
             if v.0.token_type != TokenType::Symbol {
-                return (vec![], Some("Contract input name is not a symbol".to_string()))
+                self.error(
+                    format!("Witness name `{}` is not a symbol.", v.0.token),
+                    v.0.line,
+                    v.0.column,
+                );
             }
 
             if v.1.token_type != TokenType::Symbol {
-                return (vec![], Some("Contract input type is not a symbol".to_string()))
+                self.error(
+                    format!("Witness type `{}` is not a symbol.", v.1.token),
+                    v.1.line,
+                    v.1.column,
+                );
             }
 
             match v.1.token.as_str() {
@@ -357,6 +419,7 @@ impl Parser {
                         column: v.0.column,
                     });
                 }
+
                 "Scalar" => {
                     ret.push(Witness {
                         name: k.to_string(),
@@ -365,6 +428,7 @@ impl Parser {
                         column: v.0.column,
                     });
                 }
+
                 "MerklePath" => {
                     ret.push(Witness {
                         name: k.to_string(),
@@ -373,14 +437,14 @@ impl Parser {
                         column: v.0.column,
                     });
                 }
+
                 x => {
-                    let err_msg = format!("`{}` is an illegal witness type", x);
-                    return (vec![], Some(err_msg))
+                    self.error(format!("`{}` is an illegal witness type", x), v.1.line, v.1.column);
                 }
             }
         }
 
-        (ret, None)
+        ret
     }
 
     fn error(&self, msg: String, ln: usize, col: usize) {

+ 1 - 0
zkas/src/types.rs

@@ -1,3 +1,4 @@
+/// Types supported by the VM
 #[derive(Clone, Debug)]
 pub enum Type {
     EcFixedPoint = 0x00,