Просмотр исходного кода

zkas/parser: Improve and clean up, and remove circuit parsing.

It is rewritten in the next commit.
Luther Blissett 4 лет назад
Родитель
Сommit
024414be98
1 измененных файлов с 239 добавлено и 395 удалено
  1. 239 395
      src/zkas/parser.rs

+ 239 - 395
src/zkas/parser.rs

@@ -1,20 +1,28 @@
-use std::{iter::Peekable, str::Chars};
+use std::str::Chars;
 
-use fxhash::FxBuildHasher;
 use indexmap::IndexMap;
 use itertools::Itertools;
 
 use super::{
-    ast::{
-        Constant, Constants, Statement, StatementType, Statements, UnparsedConstants,
-        UnparsedWitnesses, Variable, Witness, Witnesses,
-    },
+    ast::{Constant, Statement, Witness},
     error::ErrorEmitter,
     lexer::{Token, TokenType},
-    opcode::Opcode,
-    types::Type,
+    LitType, VarType,
 };
 
+/// zkas language builtin keywords.
+/// These can not be used anywhere except where they are expected.
+const KEYWORDS: [&str; 3] = ["constant", "contract", "circuit"];
+
+/// Valid EcFixedPoint constant names supported by the VM.
+const VALID_ECFIXEDPOINT: [&str; 1] = ["VALUE_COMMIT_RANDOM"];
+
+/// Valid EcFixedPointShort constant names supported by the VM.
+const VALID_ECFIXEDPOINTSHORT: [&str; 1] = ["VALUE_COMMIT_VALUE"];
+
+/// Valid EcFixedPointBase constant names supported by the VM.
+const VALID_ECFIXEDPOINTBASE: [&str; 1] = ["NULLIFIER_K"];
+
 pub struct Parser {
     tokens: Vec<Token>,
     error: ErrorEmitter,
@@ -27,127 +35,127 @@ impl Parser {
         let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
         let error = ErrorEmitter::new("Parser", filename, lines);
 
-        Parser { tokens, error }
+        Self { tokens, error }
     }
 
-    pub fn parse(self) -> (Constants, Witnesses, Statements) {
-        // We use these to keep state when iterating
+    pub fn parse(&self) -> (Vec<Constant>, Vec<Witness>, Vec<Statement>) {
+        // We use these to keep state while parsing.
+        let mut namespace = None;
         let (mut declaring_constant, mut declared_constant) = (false, false);
         let (mut declaring_contract, mut declared_contract) = (false, false);
         let (mut declaring_circuit, mut declared_circuit) = (false, false);
 
+        // The tokens gathered from each of the sections
         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 = IndexMap::with_hasher(FxBuildHasher::default());
-        let mut namespace = String::new();
+        let mut circuit_stmt = vec![];
+        let mut circuit_stmts = vec![];
         let mut ast_inner = IndexMap::new();
-        let mut namespace_found = false; // Nasty
+        let mut ast = IndexMap::new();
+
+        if self.tokens[0].token_type != TokenType::Symbol {
+            self.error.abort(
+                "Source file does not start with a section. Expected `constant/contract/circuit`.",
+                0,
+                0,
+            );
+        }
 
         let mut iter = self.tokens.iter();
         while let Some(t) = iter.next() {
-            // Start by declaring a section
+            // Sections "constant", "contract", and "circuit" are
+            // the sections we must be declaring in our source code.
+            // When we find one, we'll take all the tokens found in
+            // the section and place them in their respective vec.
+            // NOTE: Currently this logic depends on the fact that
+            // the sections are closed off with braces. This should
+            // be revisited later when we decide to add other lang
+            // functionality that also depends on using braces.
             if !declaring_constant && !declaring_contract && !declaring_circuit {
-                if t.token_type != TokenType::Symbol {
-                    self.error.abort(
-                        "Source file does not start with a section.
-Expected `constant/contract/circuit`.",
-                        0,
-                        0,
-                    );
-                }
-
-                // The sections we must be declaring in our source code
-                match t.token.as_str() {
-                    "constant" => {
-                        declaring_constant = true;
-                        // Eat all the tokens within the `constant` section
+                //
+                // We use this macro to avoid code repetition in the following
+                // match statement for soaking up the section tokens.
+                macro_rules! absorb_inner_tokens {
+                    ($v:ident) => {
                         for inner in iter.by_ref() {
-                            constant_tokens.push(inner.clone());
+                            if KEYWORDS.contains(&inner.token.as_str()) &&
+                                inner.token_type == TokenType::Symbol
+                            {
+                                self.error.abort(
+                                    &format!("Keyword '{}' used in improper place.", inner.token),
+                                    inner.line,
+                                    inner.column,
+                                );
+                            }
+
+                            $v.push(inner.clone());
                             if inner.token_type == TokenType::RightBrace {
                                 break
                             }
                         }
-                    }
+                    };
+                }
 
+                match t.token.as_str() {
+                    "constant" => {
+                        declaring_constant = true;
+                        absorb_inner_tokens!(constant_tokens);
+                    }
                     "contract" => {
                         declaring_contract = true;
-                        // Eat all the tokens within the `contract` section
-                        for inner in iter.by_ref() {
-                            contract_tokens.push(inner.clone());
-                            if inner.token_type == TokenType::RightBrace {
-                                break
-                            }
-                        }
+                        absorb_inner_tokens!(contract_tokens);
                     }
-
                     "circuit" => {
                         declaring_circuit = true;
-                        // Eat all the tokens within the `circuit` section
-                        // TODO: Revisit when we support if/else and loops
-                        for inner in iter.by_ref() {
-                            circuit_tokens.push(inner.clone());
-                            if inner.token_type == TokenType::RightBrace {
-                                break
-                            }
-                        }
+                        absorb_inner_tokens!(circuit_tokens);
                     }
 
                     x => self.error.abort(
-                        &format!("Unknown `{}` proof section", x),
+                        &format!("Section `{}` is not a valid section", x),
                         t.line,
                         t.column,
                     ),
                 }
             }
 
-            // We shouldn't be reaching these states
-            if declaring_constant && (declaring_contract || declaring_circuit) {
-                unreachable!()
-            }
-            if declaring_contract && (declaring_constant || declaring_circuit) {
-                unreachable!()
-            }
-            if declaring_circuit && (declaring_constant || declaring_contract) {
-                unreachable!()
+            // We use this macro to set or check that the namespace of all sections
+            // is the same and no stray strings appeared.
+            macro_rules! check_namespace {
+                ($t:ident) => {
+                    if let Some(ns) = namespace.clone() {
+                        if ns != $t[0].token {
+                            self.error.abort(
+                                &format!("Found '{}' namespace, expected '{}'.", $t[0].token, ns),
+                                $t[0].line,
+                                $t[0].column,
+                            );
+                        }
+                    } else {
+                        namespace = Some($t[0].token.clone());
+                    }
+                };
             }
 
-            // Now go through the token vectors and work it through
+            // Parse the constant section into the AST.
             if declaring_constant {
                 if declared_constant {
-                    self.error.abort("Duplicate `constant` section found", 0, 0);
+                    self.error.abort("Duplicate `constant` section found.", t.line, t.column);
                 }
-                self.check_section_structure("constant", constant_tokens.clone());
 
-                if namespace_found && namespace != constant_tokens[0].token {
-                    self.error.abort(
-                        &format!(
-                            "Found `{}` namespace. Expected `{}`.",
-                            constant_tokens[0].token, namespace
-                        ),
-                        constant_tokens[0].line,
-                        constant_tokens[0].column,
-                    );
-                } else {
-                    namespace = constant_tokens[0].token.clone();
-                    namespace_found = true;
-                }
+                self.check_section_structure("constant", constant_tokens.clone());
+                check_namespace!(constant_tokens);
 
-                let constants_cloned = constant_tokens.clone();
                 let mut constants_map = IndexMap::new();
-                // This is everything between the braces: { .. }
-                let mut constants_inner = constants_cloned[2..constant_tokens.len() - 1].iter();
-
-                while let Some((typ, name, comma)) = constants_inner.next_tuple() {
+                // This is everything between the braces: { ... }
+                let mut constant_inner = constant_tokens[2..constant_tokens.len() - 1].iter();
+                while let Some((typ, name, comma)) = constant_inner.next_tuple() {
                     if comma.token_type != TokenType::Comma {
-                        self.error.abort("Separator is not a comma", comma.line, comma.column);
+                        self.error.abort("Separator is not a comma.", comma.line, comma.column);
                     }
 
+                    // No variable shadowing
                     if constants_map.contains_key(name.token.as_str()) {
                         self.error.abort(
                             &format!(
@@ -162,42 +170,34 @@ Expected `constant/contract/circuit`.",
                     constants_map.insert(name.token.clone(), (name.clone(), typ.clone()));
                 }
 
+                if let Some(_) = constant_inner.next() {
+                    self.error.abort("Internal error, leftovers in 'constant' iterator", 0, 0);
+                }
+
                 ast_inner.insert("constant".to_string(), constants_map);
                 declaring_constant = false;
                 declared_constant = true;
             }
 
+            // Parse the contract section into the AST.
             if declaring_contract {
                 if declared_contract {
-                    self.error.abort("Duplicate `contract` section found", 0, 0);
+                    self.error.abort("Duplicate `contract` section found.", t.line, t.column);
                 }
-                self.check_section_structure("contract", contract_tokens.clone());
 
-                if namespace_found && namespace != contract_tokens[0].token {
-                    self.error.abort(
-                        &format!(
-                            "Found `{}` namespace. Expected `{}`.",
-                            contract_tokens[0].token, namespace
-                        ),
-                        contract_tokens[0].line,
-                        contract_tokens[0].column,
-                    );
-                } else {
-                    namespace = contract_tokens[0].token.clone();
-                    namespace_found = true;
-                }
-
-                let contract_cloned = contract_tokens.clone();
-                let mut contract_map = IndexMap::new();
-                // This is everything between the braces: { .. }
-                let mut contract_inner = contract_cloned[2..contract_tokens.len() - 1].iter();
+                self.check_section_structure("contract", contract_tokens.clone());
+                check_namespace!(contract_tokens);
 
+                let mut witnesses_map = IndexMap::new();
+                // This is everything between the braces: { ... }
+                let mut contract_inner = contract_tokens[2..contract_tokens.len() - 1].iter();
                 while let Some((typ, name, comma)) = contract_inner.next_tuple() {
                     if comma.token_type != TokenType::Comma {
-                        self.error.abort("Separator is not a comma", comma.line, comma.column);
+                        self.error.abort("Separator is not a comma.", comma.line, comma.column);
                     }
 
-                    if contract_map.contains_key(name.token.as_str()) {
+                    // No variable shadowing
+                    if witnesses_map.contains_key(name.token.as_str()) {
                         self.error.abort(
                             &format!(
                                 "Section `contract` already contains the token `{}`.",
@@ -208,50 +208,34 @@ Expected `constant/contract/circuit`.",
                         );
                     }
 
-                    contract_map.insert(name.token.clone(), (name.clone(), typ.clone()));
+                    witnesses_map.insert(name.token.clone(), (name.clone(), typ.clone()));
+                }
+
+                if let Some(_) = contract_inner.next() {
+                    self.error.abort("Internal error, leftovers in 'contract' iterator", 0, 0);
                 }
 
-                ast_inner.insert("contract".to_string(), contract_map);
+                ast_inner.insert("contract".to_string(), witnesses_map);
                 declaring_contract = false;
                 declared_contract = true;
             }
 
+            // Parse the circuit section into the AST.
             if declaring_circuit {
                 if declared_circuit {
-                    self.error.abort("Duplicate `circuit` section found", 0, 0);
+                    self.error.abort("Duplicate `circuit` section found.", t.line, t.column);
                 }
-                self.check_section_structure("circuit", contract_tokens.clone());
 
-                if circuit_tokens[circuit_tokens.len() - 2].token_type != TokenType::Semicolon {
-                    self.error.abort(
-                        "Circuit section does not end with a semicolon. Would never finish parsing.",
-                        circuit_tokens[circuit_tokens.len()-2].line,
-                        circuit_tokens[circuit_tokens.len()-2].column
-                    );
-                }
+                self.check_section_structure("circuit", circuit_tokens.clone());
+                check_namespace!(circuit_tokens);
 
-                if namespace_found && namespace != circuit_tokens[0].token {
-                    self.error.abort(
-                        &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()[2..circuit_tokens.len() - 1].iter() {
+                for i in circuit_tokens[2..circuit_tokens.len() - 1].iter() {
                     if i.token_type == TokenType::Semicolon {
-                        circuit_statements.push(circuit_statement.clone());
-                        // println!("{:?}", circuit_statement);
-                        circuit_statement = vec![];
+                        circuit_stmts.push(circuit_stmt.clone());
+                        circuit_stmt = vec![];
                         continue
                     }
-                    circuit_statement.push(i.clone());
+                    circuit_stmt.push(i.clone());
                 }
 
                 declaring_circuit = false;
@@ -259,49 +243,43 @@ Expected `constant/contract/circuit`.",
             }
         }
 
-        ast.insert(namespace.clone(), ast_inner);
-        // TODO: Check that there are no duplicate names in constants, contract
-        //       and circuit assignments
+        let ns = namespace.unwrap();
+        ast.insert(ns.clone(), ast_inner);
 
-        // Clean up the `constant` section
-        let c = match ast.get(&namespace).unwrap().get("constant") {
-            Some(c) => c,
-            None => {
-                self.error.abort("Missing `constant` section in .zk source", 0, 0);
-                unreachable!()
-            }
+        let constants = {
+            let c = match ast.get(&ns).unwrap().get("constant") {
+                Some(c) => c,
+                None => {
+                    self.error.abort("Missing `constant` section in .zk source.", 0, 0);
+                    unreachable!();
+                }
+            };
+            self.parse_ast_constants(c)
         };
-        let constants = self.parse_ast_constants(c);
-        if constants.is_empty() {
-            self.error.warn("Constant section is empty", 0, 0);
-        }
 
-        // Clean up the `contract` section
-        let c = match ast.get(&namespace).unwrap().get("contract") {
-            Some(c) => c,
-            None => {
-                self.error.abort("Missing `contract` section in .zk source", 0, 0);
-                unreachable!()
-            }
+        let witnesses = {
+            let c = match ast.get(&ns).unwrap().get("contract") {
+                Some(c) => c,
+                None => {
+                    self.error.abort("Missing `contract` section in .zk source.", 0, 0);
+                    unreachable!();
+                }
+            };
+            self.parse_ast_contract(c)
         };
-        let witnesses = self.parse_ast_contract(c);
-        if witnesses.is_empty() {
-            self.error.abort("Contract section is empty", 0, 0);
-        }
 
-        // Clean up the `circuit` section
-        let stmt = self.parse_ast_circuit(circuit_statements);
-        if stmt.is_empty() {
-            self.error.abort("Circuit section is empty", 0, 0);
+        let statements = self.parse_ast_circuit(circuit_stmts);
+        if statements.is_empty() {
+            self.error.abort("Circuit section is empty.", 0, 0);
         }
 
-        (constants, witnesses, stmt)
+        (constants, witnesses, statements)
     }
 
     fn check_section_structure(&self, section: &str, tokens: Vec<Token>) {
         if tokens[0].token_type != TokenType::String {
             self.error.abort(
-                &format!("{} section declaration must start with a naming string.", section),
+                "Section declaration must start with a naming string.",
                 tokens[0].line,
                 tokens[0].column,
             );
@@ -309,43 +287,56 @@ Expected `constant/contract/circuit`.",
 
         if tokens[1].token_type != TokenType::LeftBrace {
             self.error.abort(
-                &format!(
-                    "{} section opening is not correct. Must be opened with a left brace `{{`",
-                    section
-                ),
+                "Section must be opened with a left brace '{'",
                 tokens[0].line,
                 tokens[0].column,
             );
         }
 
-        if tokens[tokens.len() - 1].token_type != TokenType::RightBrace {
+        if tokens.last().unwrap().token_type != TokenType::RightBrace {
             self.error.abort(
-                &format!(
-                    "{} section closing is not correct. Must be closed with a right brace `}}`",
-                    section
-                ),
+                "Section must be closed with a right brace '}'",
                 tokens[0].line,
                 tokens[0].column,
             );
         }
 
-        if (section == "constant" || section == "contract") &&
-            tokens[2..tokens.len() - 1].len() % 3 != 0
-        {
-            self.error.abort(
-                &format!(
-                    "Invalid number of elements in `{}` section. Must be pairs of `type:name` separated with a comma `,`",
-                    section
-                ),
-                tokens[0].line,
-                tokens[0].column,
-            );
-        }
+        match section {
+            "constant" | "contract" => {
+                if tokens.len() == 3 {
+                    self.error.warn(&format!("{} section is empty.", section), 0, 0);
+                }
+
+                if tokens[2..tokens.len() - 1].len() % 3 != 0 {
+                    self.error.abort(
+                        &format!("Invalid number of elements in '{}' section. Must be pairs of '<Type> <name>' separated with a comma ','.", section),
+                        tokens[0].line,
+                        tokens[0].column
+                    );
+                }
+            }
+            "circuit" => {
+                if tokens.len() == 3 {
+                    self.error.abort("circuit section is empty.", 0, 0);
+                }
+
+                if tokens[tokens.len() - 2].token_type != TokenType::Semicolon {
+                    self.error.abort(
+                        "Circuit section does not end with a semicolon. Would never finish parsing.",
+                        tokens[tokens.len()-2].line,
+                        tokens[tokens.len()-2].column,
+                    );
+                }
+            }
+            _ => panic!(),
+        };
     }
 
-    fn parse_ast_constants(&self, ast: &UnparsedConstants) -> Constants {
+    fn parse_ast_constants(&self, ast: &IndexMap<String, (Token, Token)>) -> Vec<Constant> {
         let mut ret = vec![];
 
+        // k = name
+        // v = (name, type)
         for (k, v) in ast {
             if &v.0.token != k {
                 self.error.abort(
@@ -371,37 +362,75 @@ Expected `constant/contract/circuit`.",
                 );
             }
 
+            // Valid constant types, these are the constants/generators supported
+            // in `src/crypto/constants.rs` and `src/crypto/constants/`.
             match v.1.token.as_str() {
                 "EcFixedPoint" => {
+                    if !VALID_ECFIXEDPOINT.contains(&v.0.token.as_str()) {
+                        self.error.abort(
+                            &format!(
+                                "`{}` is not a valid EcFixedPoint constant. Supported: {:?}",
+                                v.0.token.as_str(),
+                                VALID_ECFIXEDPOINT
+                            ),
+                            v.0.line,
+                            v.0.column,
+                        );
+                    }
+
                     ret.push(Constant {
                         name: k.to_string(),
-                        typ: Type::EcFixedPoint,
-                        line: v.0.line,
-                        column: v.0.column,
+                        typ: VarType::EcFixedPoint,
+                        line: v.1.line,
+                        column: v.1.column,
                     });
                 }
 
                 "EcFixedPointShort" => {
+                    if !VALID_ECFIXEDPOINTSHORT.contains(&v.0.token.as_str()) {
+                        self.error.abort(
+                            &format!(
+                                "`{}` is not a valid EcFixedPointShort constant. Supported: {:?}",
+                                v.0.token.as_str(),
+                                VALID_ECFIXEDPOINTSHORT
+                            ),
+                            v.0.line,
+                            v.0.column,
+                        );
+                    }
+
                     ret.push(Constant {
                         name: k.to_string(),
-                        typ: Type::EcFixedPointShort,
-                        line: v.0.line,
-                        column: v.0.column,
+                        typ: VarType::EcFixedPointShort,
+                        line: v.1.line,
+                        column: v.1.column,
                     });
                 }
 
                 "EcFixedPointBase" => {
+                    if !VALID_ECFIXEDPOINTBASE.contains(&v.0.token.as_str()) {
+                        self.error.abort(
+                            &format!(
+                                "`{}` is not a valid EcFixedPointBase constant. Supported: {:?}",
+                                v.0.token.as_str(),
+                                VALID_ECFIXEDPOINTBASE
+                            ),
+                            v.0.line,
+                            v.0.column,
+                        );
+                    }
+
                     ret.push(Constant {
                         name: k.to_string(),
-                        typ: Type::EcFixedPointBase,
-                        line: v.0.line,
-                        column: v.0.column,
+                        typ: VarType::EcFixedPointBase,
+                        line: v.1.line,
+                        column: v.1.column,
                     });
                 }
 
                 x => {
                     self.error.abort(
-                        &format!("`{}` is an illegal constant type", x),
+                        &format!("`{}` is an unsupported constant type.", x),
                         v.1.line,
                         v.1.column,
                     );
@@ -412,9 +441,11 @@ Expected `constant/contract/circuit`.",
         ret
     }
 
-    fn parse_ast_contract(&self, ast: &UnparsedWitnesses) -> Witnesses {
+    fn parse_ast_contract(&self, ast: &IndexMap<String, (Token, Token)>) -> Vec<Witness> {
         let mut ret = vec![];
 
+        // k = name
+        // v = (name, type)
         for (k, v) in ast {
             if &v.0.token != k {
                 self.error.abort(
@@ -440,11 +471,12 @@ Expected `constant/contract/circuit`.",
                 );
             }
 
+            // Valid witness types
             match v.1.token.as_str() {
                 "Base" => {
                     ret.push(Witness {
                         name: k.to_string(),
-                        typ: Type::Base,
+                        typ: VarType::Base,
                         line: v.0.line,
                         column: v.0.column,
                     });
@@ -453,7 +485,7 @@ Expected `constant/contract/circuit`.",
                 "Scalar" => {
                     ret.push(Witness {
                         name: k.to_string(),
-                        typ: Type::Scalar,
+                        typ: VarType::Scalar,
                         line: v.0.line,
                         column: v.0.column,
                     });
@@ -462,7 +494,7 @@ Expected `constant/contract/circuit`.",
                 "MerklePath" => {
                     ret.push(Witness {
                         name: k.to_string(),
-                        typ: Type::MerklePath,
+                        typ: VarType::MerklePath,
                         line: v.0.line,
                         column: v.0.column,
                     });
@@ -471,7 +503,7 @@ Expected `constant/contract/circuit`.",
                 "Uint32" => {
                     ret.push(Witness {
                         name: k.to_string(),
-                        typ: Type::Uint32,
+                        typ: VarType::Uint32,
                         line: v.0.line,
                         column: v.0.column,
                     });
@@ -480,7 +512,7 @@ Expected `constant/contract/circuit`.",
                 "Uint64" => {
                     ret.push(Witness {
                         name: k.to_string(),
-                        typ: Type::Uint64,
+                        typ: VarType::Uint64,
                         line: v.0.line,
                         column: v.0.column,
                     });
@@ -488,7 +520,7 @@ Expected `constant/contract/circuit`.",
 
                 x => {
                     self.error.abort(
-                        &format!("`{}` is an illegal witness type", x),
+                        &format!("`{}` is an unsupported witness type.", x),
                         v.1.line,
                         v.1.column,
                     );
@@ -500,196 +532,8 @@ Expected `constant/contract/circuit`.",
     }
 
     fn parse_ast_circuit(&self, statements: Vec<Vec<Token>>) -> Vec<Statement> {
-        let mut stmts = vec![];
-
-        for statement in statements {
-            let (mut left_paren, mut right_paren) = (0, 0);
-            for i in &statement {
-                match i.token.as_str() {
-                    "(" => left_paren += 1,
-                    ")" => right_paren += 1,
-                    _ => {}
-                }
-            }
-            if left_paren != right_paren {
-                self.error.abort(
-                    "Incorrect number of left and right parenthesis for statement.",
-                    statement[0].line,
-                    statement[0].column,
-                );
-            }
-
-            // C = poseidon_hash(pub_x, pub_y, value, token, serial, coin_blind)
-            // | |         |                     |
-            // V V         V                     V
-            // variable   opcode                args
-            // assign
-
-            // constrain_instance(C)
-            //     |              |
-            //     V              V
-            //   opcode         args
-
-            let mut iter = statement.iter().peekable();
-            let mut stmt = Statement::default();
-
-            let mut parsing = false;
-
-            while let Some(token) = iter.next() {
-                if !parsing {
-                    if let Some(next_token) = iter.peek() {
-                        if next_token.token_type == TokenType::Assign {
-                            stmt.typ = StatementType::Assignment;
-                            stmt.variable = Some(Variable {
-                                name: token.token.clone(),
-                                typ: Type::Dummy,
-                                line: token.line,
-                                column: token.column,
-                            });
-                            // Skip over the `=` token.
-                            iter.next();
-                            parsing = true;
-                            continue
-                        }
-
-                        if next_token.token_type == TokenType::LeftParen {
-                            stmt.typ = StatementType::Call;
-                            stmt.variable = None;
-                            parsing = true;
-                        }
-
-                        if !parsing {
-                            self.error.abort(
-                                &format!("Illegal token `{}`", next_token.token),
-                                next_token.line,
-                                next_token.column,
-                            );
-                        }
-                    }
-                }
-
-                // This matching could be moved over into the semantic analyzer.
-                // We could just parse any kind of symbol here, and then do lookup
-                // from the analyzer, to see if the calls actually exist and are
-                // supported.
-                // But for now, we'll just leave it here and expand later.
-                let func_name = token.token.as_str();
-
-                macro_rules! parse_func {
-                    ($opcode: expr) => {
-                        stmt.args = self.parse_function_call(token, &mut iter);
-                        stmt.opcode = $opcode;
-                        stmt.line = token.line;
-                        stmts.push(stmt.clone());
-
-                        parsing = false;
-                        continue
-                    };
-                }
-
-                match func_name {
-                    "poseidon_hash" => {
-                        parse_func!(Opcode::PoseidonHash);
-                    }
-
-                    "constrain_instance" => {
-                        parse_func!(Opcode::ConstrainInstance);
-                    }
-
-                    "calculate_merkle_root" => {
-                        parse_func!(Opcode::CalculateMerkleRoot);
-                    }
-
-                    "ec_mul_short" => {
-                        parse_func!(Opcode::EcMulShort);
-                    }
-
-                    "ec_mul_base" => {
-                        parse_func!(Opcode::EcMulBase);
-                    }
-
-                    "ec_mul" => {
-                        parse_func!(Opcode::EcMul);
-                    }
-
-                    "ec_get_x" => {
-                        parse_func!(Opcode::EcGetX);
-                    }
-
-                    "ec_get_y" => {
-                        parse_func!(Opcode::EcGetY);
-                    }
-
-                    "ec_add" => {
-                        parse_func!(Opcode::EcAdd);
-                    }
-
-                    "base_add" => {
-                        parse_func!(Opcode::BaseAdd);
-                    }
-
-                    "base_mul" => {
-                        parse_func!(Opcode::BaseMul);
-                    }
-
-                    "base_sub" => {
-                        parse_func!(Opcode::BaseSub);
-                    }
-
-                    x => {
-                        self.error.abort(
-                            &format!("Unimplemented function call `{}`", x),
-                            token.line,
-                            token.column,
-                        );
-                    }
-                }
-            }
-        }
-
-        // println!("{:#?}", stmts);
-        stmts
-    }
-
-    fn parse_function_call(
-        &self,
-        token: &Token,
-        iter: &mut Peekable<std::slice::Iter<'_, Token>>,
-    ) -> Vec<Variable> {
-        if let Some(next_token) = iter.peek() {
-            if next_token.token_type != TokenType::LeftParen {
-                self.error.abort(
-                    "Invalid function call opening. Must start with a `(`",
-                    next_token.line,
-                    next_token.column,
-                );
-            }
-            // Skip the opening parenthesis
-            iter.next();
-        } else {
-            self.error.abort("Premature ending of statement", token.line, token.column);
-        }
-
-        // Eat up function arguments
-        let mut args = vec![];
-        while let Some((arg, sep)) = iter.next_tuple() {
-            args.push(Variable {
-                name: arg.token.clone(),
-                typ: Type::Dummy,
-                line: arg.line,
-                column: arg.column,
-            });
-
-            if sep.token_type == TokenType::RightParen {
-                // Reached end of args
-                break
-            }
-
-            if sep.token_type != TokenType::Comma {
-                self.error.abort("Argument separator is not a comma (`,`)", sep.line, sep.column);
-            }
-        }
+        let mut ret = vec![];
 
-        args
+        ret
     }
 }