Sfoglia il codice sorgente

zkas: Number parsing, and be more explicit about sections.

Luther Blissett 4 anni fa
parent
commit
d204c2256d
2 ha cambiato i file con 86 aggiunte e 56 eliminazioni
  1. 65 47
      src/zkas/lexer.rs
  2. 21 9
      src/zkas/parser.rs

+ 65 - 47
src/zkas/lexer.rs

@@ -6,13 +6,13 @@ use super::error::ErrorEmitter;
 pub enum TokenType {
     Symbol,
     String,
+    Number,
     LeftBrace,
     RightBrace,
     LeftParen,
     RightParen,
     Comma,
     Semicolon,
-    Colon,
     Assign,
 }
 
@@ -27,8 +27,8 @@ pub struct Token {
 }
 
 impl Token {
-    fn new(token: String, token_type: TokenType, line: usize, column: usize) -> Self {
-        Token { token, token_type, line, column }
+    fn new(token: &str, token_type: TokenType, line: usize, column: usize) -> Self {
+        Token { token: token.to_string(), token_type, line, column }
     }
 }
 
@@ -55,10 +55,12 @@ impl<'a> Lexer<'a> {
         // We use these as a buffer to keep strings and symbols
         let mut strbuf = String::new();
         let mut symbuf = String::new();
+        let mut numbuf = String::new();
 
         // We use these to keep state when iterating
         let mut in_comment = false;
         let mut in_string = false;
+        let mut in_number = false;
         let mut in_symbol = false;
 
         #[allow(clippy::explicit_counter_loop)]
@@ -69,7 +71,7 @@ impl<'a> Lexer<'a> {
                 if in_symbol {
                     in_symbol = false;
                     tokens.push(Token::new(
-                        symbuf.clone(),
+                        &symbuf,
                         TokenType::Symbol,
                         lineno,
                         column - symbuf.len(),
@@ -78,9 +80,16 @@ impl<'a> Lexer<'a> {
                 }
 
                 if in_string {
-                    // TODO: Allow newlines in strings?
                     self.error.abort(
-                        &format!("Invalid ending in string `{}`", &strbuf),
+                        &format!("Strings can not contain newlines: `{}`", &strbuf),
+                        lineno,
+                        column,
+                    );
+                }
+
+                if in_number {
+                    self.error.abort(
+                        &format!("Numbers can not contain newlines: `{}`", &numbuf),
                         lineno,
                         column,
                     );
@@ -96,7 +105,7 @@ impl<'a> Lexer<'a> {
                 if in_symbol {
                     in_symbol = false;
                     tokens.push(Token::new(
-                        symbuf.clone(),
+                        &symbuf,
                         TokenType::Symbol,
                         lineno,
                         column - symbuf.len(),
@@ -117,7 +126,7 @@ impl<'a> Lexer<'a> {
                 if in_symbol {
                     in_symbol = false;
                     tokens.push(Token::new(
-                        symbuf.clone(),
+                        &symbuf,
                         TokenType::Symbol,
                         lineno,
                         column - symbuf.len(),
@@ -125,9 +134,26 @@ impl<'a> Lexer<'a> {
                     symbuf = String::new();
                 }
 
+                if in_number {
+                    in_number = false;
+                    tokens.push(Token::new(
+                        &numbuf,
+                        TokenType::Number,
+                        lineno,
+                        column - numbuf.len(),
+                    ));
+                    numbuf = String::new();
+                }
+
                 continue
             }
 
+            if in_number && !is_digit(c) {
+                in_number = false;
+                tokens.push(Token::new(&numbuf, TokenType::Number, lineno, column - numbuf.len()));
+                numbuf = String::new();
+            }
+
             if !in_string && is_letter(c) {
                 in_symbol = true;
                 symbuf.push(c);
@@ -139,11 +165,22 @@ impl<'a> Lexer<'a> {
                 continue
             }
 
+            if in_number && is_digit(c) {
+                numbuf.push(c);
+                continue
+            }
+
             if in_symbol && is_digit(c) {
                 symbuf.push(c);
                 continue
             }
 
+            if !in_symbol && !in_string && !in_number && is_digit(c) {
+                in_number = true;
+                numbuf.push(c);
+                continue
+            }
+
             if c == '"' && !in_string {
                 if in_symbol {
                     self.error.abort(&format!("Illegal char `{}` for symbol", c), lineno, column);
@@ -162,12 +199,7 @@ impl<'a> Lexer<'a> {
                 }
 
                 in_string = false;
-                tokens.push(Token::new(
-                    strbuf.clone(),
-                    TokenType::String,
-                    lineno,
-                    column - strbuf.len(),
-                ));
+                tokens.push(Token::new(&strbuf, TokenType::String, lineno, column - strbuf.len()));
                 strbuf = String::new();
                 continue
             }
@@ -176,7 +208,7 @@ impl<'a> Lexer<'a> {
                 if in_symbol {
                     in_symbol = false;
                     tokens.push(Token::new(
-                        symbuf.clone(),
+                        &symbuf,
                         TokenType::Symbol,
                         lineno,
                         column - symbuf.len(),
@@ -184,58 +216,44 @@ impl<'a> Lexer<'a> {
                     symbuf = String::new();
                 }
 
+                if in_number {
+                    in_number = false;
+                    tokens.push(Token::new(
+                        &numbuf,
+                        TokenType::Symbol,
+                        lineno,
+                        column - numbuf.len(),
+                    ));
+                    numbuf = String::new();
+                }
+
                 match c {
                     '{' => {
-                        tokens.push(Token::new(
-                            "{".to_string(),
-                            TokenType::LeftBrace,
-                            lineno,
-                            column,
-                        ));
+                        tokens.push(Token::new("{", TokenType::LeftBrace, lineno, column));
                         continue
                     }
                     '}' => {
-                        tokens.push(Token::new(
-                            "}".to_string(),
-                            TokenType::RightBrace,
-                            lineno,
-                            column,
-                        ));
+                        tokens.push(Token::new("}", TokenType::RightBrace, lineno, column));
                         continue
                     }
                     '(' => {
-                        tokens.push(Token::new(
-                            "(".to_string(),
-                            TokenType::LeftParen,
-                            lineno,
-                            column,
-                        ));
+                        tokens.push(Token::new("(", TokenType::LeftParen, lineno, column));
                         continue
                     }
                     ')' => {
-                        tokens.push(Token::new(
-                            ")".to_string(),
-                            TokenType::RightParen,
-                            lineno,
-                            column,
-                        ));
+                        tokens.push(Token::new(")", TokenType::RightParen, lineno, column));
                         continue
                     }
                     ',' => {
-                        tokens.push(Token::new(",".to_string(), TokenType::Comma, lineno, column));
+                        tokens.push(Token::new(",", TokenType::Comma, lineno, column));
                         continue
                     }
                     ';' => {
-                        tokens.push(Token::new(
-                            ";".to_string(),
-                            TokenType::Semicolon,
-                            lineno,
-                            column,
-                        ));
+                        tokens.push(Token::new(";", TokenType::Semicolon, lineno, column));
                         continue
                     }
                     '=' => {
-                        tokens.push(Token::new("=".to_string(), TokenType::Assign, lineno, column));
+                        tokens.push(Token::new("=", TokenType::Assign, lineno, column));
                         continue
                     }
                     _ => self.error.abort(&format!("Invalid token `{}`", c), lineno, column - 1),

+ 21 - 9
src/zkas/parser.rs

@@ -32,9 +32,9 @@ impl Parser {
 
     pub fn parse(self) -> (Constants, Witnesses, Statements) {
         // We use these to keep state when iterating
-        let mut declaring_constant = false;
-        let mut declaring_contract = false;
-        let mut declaring_circuit = false;
+        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);
 
         let mut constant_tokens = vec![];
         let mut contract_tokens = vec![];
@@ -54,9 +54,12 @@ impl Parser {
             // Start by declaring a section
             if !declaring_constant && !declaring_contract && !declaring_circuit {
                 if t.token_type != TokenType::Symbol {
-                    // TODO: Revisit
-                    // TODO: Visit this again when we are allowing imports
-                    unimplemented!();
+                    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
@@ -116,9 +119,11 @@ impl Parser {
 
             // Now go through the token vectors and work it through
             if declaring_constant {
+                if declared_constant {
+                    self.error.abort("Duplicate `constant` section found", 0, 0);
+                }
                 self.check_section_structure("constant", constant_tokens.clone());
 
-                // TODO: Do we need this?
                 if namespace_found && namespace != constant_tokens[0].token {
                     self.error.abort(
                         &format!(
@@ -159,12 +164,15 @@ impl Parser {
 
                 ast_inner.insert("constant".to_string(), constants_map);
                 declaring_constant = false;
+                declared_constant = true;
             }
 
             if declaring_contract {
+                if declared_contract {
+                    self.error.abort("Duplicate `contract` section found", 0, 0);
+                }
                 self.check_section_structure("contract", contract_tokens.clone());
 
-                // TODO: Do we need this?
                 if namespace_found && namespace != contract_tokens[0].token {
                     self.error.abort(
                         &format!(
@@ -205,9 +213,13 @@ impl Parser {
 
                 ast_inner.insert("contract".to_string(), contract_map);
                 declaring_contract = false;
+                declared_contract = true;
             }
 
             if declaring_circuit {
+                if declared_circuit {
+                    self.error.abort("Duplicate `circuit` section found", 0, 0);
+                }
                 self.check_section_structure("circuit", contract_tokens.clone());
 
                 if circuit_tokens[circuit_tokens.len() - 2].token_type != TokenType::Semicolon {
@@ -218,7 +230,6 @@ impl Parser {
                     );
                 }
 
-                // TODO: Do we need this?
                 if namespace_found && namespace != circuit_tokens[0].token {
                     self.error.abort(
                         &format!(
@@ -244,6 +255,7 @@ impl Parser {
                 }
 
                 declaring_circuit = false;
+                declared_circuit = true;
             }
         }