Эх сурвалжийг харах

zkas: Parse constants and contract.

parazyd 4 жил өмнө
parent
commit
faa88faec9

+ 16 - 0
zkas/Cargo.lock

@@ -89,6 +89,12 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
 [[package]]
 name = "hermit-abi"
 version = "0.1.19"
@@ -107,6 +113,15 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "itertools"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
+dependencies = [
+ "either",
+]
+
 [[package]]
 name = "lazy_static"
 version = "1.4.0"
@@ -290,4 +305,5 @@ dependencies = [
  "anyhow",
  "clap",
  "colour",
+ "itertools",
 ]

+ 1 - 0
zkas/Cargo.toml

@@ -11,3 +11,4 @@ edition = "2021"
 anyhow = "1.0.49"
 clap = "2.34.0"
 colour = "0.6.0"
+itertools = "0.10.3"

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

@@ -2,7 +2,7 @@ use anyhow::Result;
 use clap::clap_app;
 use std::fs::read_to_string;
 
-use zkas::lexer::lex;
+use zkas::{lexer::lex, parser::parse};
 
 fn main() -> Result<()> {
     let args = clap_app!(zkas =>
@@ -16,7 +16,7 @@ fn main() -> Result<()> {
 
     println!("{:#?}", tokens);
 
-    //let ast = parse(tokens);
+    let ast = parse(filename, source.chars(), tokens);
 
     Ok(())
 }

+ 10 - 0
zkas/src/error.rs

@@ -65,6 +65,16 @@ impl ParserError {
         ParserError::parser_error(&msg);
     }
 
+    pub fn separator_not_a_comma(&self, ln: usize, col: usize) {
+        let err_msg = format!("Invalid separator on line {} (column {})", ln, col);
+        let err_msg = format!("{}\nShould be a comma `,`", err_msg);
+        let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
+        let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
+        let caret = format!("{:width$}^", "", width = pad);
+        let msg = format!("{}\n{}\n{}", err_msg, dbg_msg, caret);
+        ParserError::parser_error(&msg);
+    }
+
     fn parser_error(msg: &str) {
         e_red!("Parser error: ");
         e_prnt_ln!("{}", msg);

+ 71 - 5
zkas/src/parser.rs

@@ -1,5 +1,7 @@
 use std::str::Chars;
 
+use itertools::Itertools;
+
 use crate::{
     error::ParserError,
     lexer::{Token, TokenType},
@@ -9,7 +11,7 @@ pub fn parse(filename: &str, source: Chars, tokens: Vec<Token>) {
     // For nice error reporting, we'll load everything into a string vector
     // so we have references to lines.
     let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
-    let _parser_error = ParserError::new(filename, lines);
+    let parser_error = ParserError::new(filename, lines);
 
     // We use these to keep state when iterating
     let mut declaring_constant = false;
@@ -30,10 +32,10 @@ pub fn parse(filename: &str, source: Chars, tokens: Vec<Token>) {
                 panic!();
             }
 
+            // The sections we are declaring in our source code
             match t.token.as_str() {
                 "constant" => {
                     declaring_constant = true;
-                    //while let Some(inner) = iter.next() {
                     for inner in iter.by_ref() {
                         constant_tokens.push(inner);
                         if inner.token_type == TokenType::RightBrace {
@@ -44,7 +46,6 @@ pub fn parse(filename: &str, source: Chars, tokens: Vec<Token>) {
 
                 "contract" => {
                     declaring_contract = true;
-                    //while let Some(inner) = iter.next() {
                     for inner in iter.by_ref() {
                         contract_tokens.push(inner);
                         if inner.token_type == TokenType::RightBrace {
@@ -55,7 +56,6 @@ pub fn parse(filename: &str, source: Chars, tokens: Vec<Token>) {
 
                 "circuit" => {
                     declaring_circuit = true;
-                    //while let Some(inner) = iter.next() {
                     for inner in iter.by_ref() {
                         circuit_tokens.push(inner);
                         if inner.token_type == TokenType::RightBrace {
@@ -64,7 +64,6 @@ pub fn parse(filename: &str, source: Chars, tokens: Vec<Token>) {
                     }
                 }
 
-                // Fall through
                 _ => unreachable!(),
             }
         }
@@ -81,5 +80,72 @@ pub fn parse(filename: &str, source: Chars, tokens: Vec<Token>) {
         }
 
         // Now go through the token vectors and work it through
+        if declaring_constant {
+            if let Some(err_msg) = check_section_structure(constant_tokens.clone()) {
+                parser_error.invalid_section_declaration(
+                    "constant",
+                    err_msg,
+                    constant_tokens[0].line,
+                    constant_tokens[0].column,
+                );
+            }
+
+            let mut constants = vec![];
+
+            let mut constants_inner = constant_tokens[2..constant_tokens.len() - 1].iter();
+            while let Some((typ, name, comma)) = constants_inner.next_tuple() {
+                if comma.token_type != TokenType::Comma {
+                    parser_error.separator_not_a_comma(comma.line, comma.column);
+                }
+                constants.push((typ, name));
+            }
+
+            declaring_constant = false;
+        }
+
+        if declaring_contract {
+            if let Some(err_msg) = check_section_structure(contract_tokens.clone()) {
+                parser_error.invalid_section_declaration(
+                    "contract",
+                    err_msg,
+                    contract_tokens[0].line,
+                    contract_tokens[0].column,
+                );
+            }
+
+            let mut contract = vec![];
+
+            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 {
+                    parser_error.separator_not_a_comma(comma.line, comma.column);
+                }
+                contract.push((typ, name));
+            }
+
+            declaring_contract = false;
+        }
+
+        if declaring_circuit {
+            declaring_circuit = false;
+        }
     }
 }
+
+fn check_section_structure(tokens: Vec<&Token>) -> Option<&str> {
+    if tokens[0].token_type != TokenType::String {
+        return Some("Section declaration must start with a naming string.")
+    }
+    if tokens[1].token_type != TokenType::LeftBrace {
+        return Some("Section opening is not correct. Must be opened with a left brace `{`")
+    }
+    if tokens[tokens.len() - 1].token_type != TokenType::RightBrace {
+        return Some("Section closing is not correct. Must be closed with a right brace `}`")
+    }
+
+    if tokens[2..tokens.len() - 1].len() % 3 != 0 {
+        return Some("Invalid number of elements in section. Must be pairs of `type:name` separated with a comma `,`")
+    }
+
+    None
+}