From 5f669059a8466dc98ad35563e61fdf93b9bdf1df Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sat, 9 Nov 2024 15:01:55 +0700 Subject: [PATCH 01/59] skip trivial first tokens in parsing --- crates/parser/src/grammar.rs | 12 ++ crates/parser/src/input.rs | 48 ++++- crates/parser/src/parser.rs | 2 +- crates/parser/src/token_kind.rs | 4 +- crates/syntax/src/lib.rs | 2 + crates/syntax/src/syntax.rs | 330 ++++++++++++++++++----------- crates/syntax/src/test_programs.rs | 135 ++++++++++++ 7 files changed, 402 insertions(+), 131 deletions(-) create mode 100644 crates/syntax/src/test_programs.rs diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 63d498f..98832cc 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -18,10 +18,22 @@ mod template; pub mod entry { + use crate::token_kind::TokenKind; + use super::*; pub fn circom_program(p: &mut Parser) { let m = p.open(); + + while p.at_any(&[ + TokenKind::BlockComment, + TokenKind::CommentLine, + TokenKind::EndLine, + TokenKind::WhiteSpace, + ]) { + p.skip(); + } + pragma::pragma(p); while !p.eof() { match p.current() { diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index 0819515..c8e17c8 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -4,7 +4,7 @@ use logos::Lexer; use crate::token_kind::TokenKind; -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct Input<'a> { kind: Vec, source: &'a str, @@ -71,7 +71,9 @@ impl<'a> Input<'a> { #[cfg(test)] mod tests { - use std::cmp::min; + // use std::cmp::min; + + use crate::token_kind::TokenKind; use super::Input; @@ -83,11 +85,45 @@ mod tests { "# .to_string(); + let expected_input = Input { + kind: vec![ + TokenKind::EndLine, + TokenKind::WhiteSpace, + TokenKind::BlockComment, + TokenKind::EndLine, + TokenKind::WhiteSpace, + TokenKind::Identifier, + TokenKind::WhiteSpace, + TokenKind::Add, + TokenKind::WhiteSpace, + TokenKind::Number, + TokenKind::EndLine, + TokenKind::WhiteSpace + ], + source: &source, + position: vec![ + {0..1}, + {1..9}, + {9..24}, + {24..25}, + {25..33}, + {33..34}, + {34..35}, + {35..36}, + {36..37}, + {37..39}, + {39..40}, + {40..44}, + ] + }; + let input = Input::new(&source); - for i in 0..min(input.size(), 10) { - println!("kind = {:?}", input.kind[i]); - println!("position {:?}", input.position[i]); - } + assert_eq!(expected_input, input, "Tokens extract from source code are not correct"); + + // for i in 0..min(input.size(), 10) { + // println!("kind = {:?}", input.kind[i]); + // println!("position {:?}", input.position[i]); + // } } } diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index e3d461c..23c4dde 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -113,7 +113,7 @@ impl<'a> Parser<'a> { let mut kind: TokenKind; loop { kind = self.input.kind_of(self.pos); - if !kind.is_travial() { + if !kind.is_trivial() { break; } diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 300028f..26145bf 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -248,10 +248,10 @@ impl TokenKind { pub fn is_declaration_kw(self) -> bool { matches!(self, Self::VarKw | Self::ComponentKw | Self::SignalKw) } - pub fn is_travial(self) -> bool { + pub fn is_trivial(self) -> bool { matches!( self, - Self::WhiteSpace | Self::EndLine | Self::CommentLine | Self::Error + Self::WhiteSpace | Self::EndLine | Self::CommentLine | Self::BlockComment | Self::Error ) } } diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 7ca0f92..adeb8b0 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -2,3 +2,5 @@ pub mod syntax; pub mod syntax_node; pub mod abstract_syntax_tree; + +pub mod test_programs; \ No newline at end of file diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 78c0ab2..3483b61 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -45,8 +45,10 @@ impl<'a> SyntaxTreeBuilder<'a> { pub fn syntax_tree(source: &str) -> SyntaxNode { let input = Input::new(source); - let mut builder = SyntaxTreeBuilder::new(&input); + let output = Parser::parsing(&input); + + let mut builder = SyntaxTreeBuilder::new(&input); builder.build(output); let green = builder.finish(); SyntaxNode::new_root(green) @@ -55,35 +57,127 @@ impl<'a> SyntaxTreeBuilder<'a> { #[cfg(test)] mod tests { - + use parser::token_kind::TokenKind::{self, *}; use std::hash::{DefaultHasher, Hash, Hasher}; - use rowan::ast::AstNode; + use rowan::{ast::AstNode, TextRange}; - use crate::abstract_syntax_tree::AstCircomProgram; + use crate::{abstract_syntax_tree::AstCircomProgram, test_programs}; use super::SyntaxTreeBuilder; + fn generate_expected_token_kind(ast: &AstCircomProgram) { + let children = ast + .syntax() + .first_child() + .unwrap() + .siblings(rowan::Direction::Next); + + println!("vec!["); + for child in children { + println!("{:?},", child.kind()); + } + println!("];"); + } + + fn generate_expected_token_range(ast: &AstCircomProgram) { + let children = ast + .syntax() + .first_child() + .unwrap() + .siblings(rowan::Direction::Next); + + println!("vec!["); + for child in children { + println!( + "TextRange::new({:?}.into(), {:?}.into()), ", + child.text_range().start(), + child.text_range().end() + ); + } + println!("];"); + } + + fn check_ast_children( + ast: &AstCircomProgram, + expected_kinds: &Vec, + expected_ranges: &Vec, + ) { + let children = ast + .syntax() + .first_child() + .unwrap() + .siblings(rowan::Direction::Next); + + let mut kind_iterator = expected_kinds.iter(); + let mut range_iterator = expected_ranges.iter(); + + for child in children { + if let (Some(expected_kind), Some(expected_range)) = + (kind_iterator.next(), range_iterator.next()) + { + assert_eq!(child.kind(), *expected_kind); + assert_eq!(child.text_range(), *expected_range); + } else { + panic!("Mismatched number of children and expected values"); + } + } + println!(); + } + #[test] - fn other_parser_test() { - let source: String = r#"pragma circom 2.0.0; + fn parser_test_1() { + let source: &str = test_programs::PARSER_TEST_1; + + let expected_pragma = "pragma circom 2.0.0;".to_string(); + let expected_kinds = vec![ + Pragma, + EndLine, + EndLine, + WhiteSpace, + EndLine, + WhiteSpace, + TemplateDef, + EndLine, + WhiteSpace, + TemplateDef, + WhiteSpace, + EndLine, + WhiteSpace, + ]; + let expected_ranges = vec![ + TextRange::new(0.into(), 20.into()), + TextRange::new(20.into(), 21.into()), + TextRange::new(21.into(), 22.into()), + TextRange::new(22.into(), 26.into()), + TextRange::new(26.into(), 27.into()), + TextRange::new(27.into(), 31.into()), + TextRange::new(31.into(), 57.into()), + TextRange::new(57.into(), 58.into()), + TextRange::new(58.into(), 62.into()), + TextRange::new(62.into(), 88.into()), + TextRange::new(88.into(), 89.into()), + TextRange::new(89.into(), 90.into()), + TextRange::new(90.into(), 94.into()), + ]; + + let syntax = SyntaxTreeBuilder::syntax_tree(source); - template Multiplier2 () {} - template Multiplier2 () {} - "# - .to_string(); + if let Some(ast) = AstCircomProgram::cast(syntax) { + check_ast_children(&ast, &expected_kinds, &expected_ranges); - let syntax = SyntaxTreeBuilder::syntax_tree(&source); + // check pragma + let pragma = ast.pragma().unwrap().syntax().text().to_string(); + assert_eq!(pragma, expected_pragma, "Pragma is not correct!"); - if let Some(ast) = AstCircomProgram::cast(syntax) { + // check ast hash let mut hasher = DefaultHasher::default(); ast.syntax().hash(&mut hasher); - // println!("{:#?}", syntax); - println!("{:?}", hasher.finish()); + let _ast_hash = hasher.finish(); + // check template hash let mut h1 = DefaultHasher::default(); - let mut h2 = DefaultHasher::default(); let template = ast.template_list(); @@ -91,124 +185,116 @@ mod tests { template[0].syntax().hash(&mut h1); template[1].syntax().hash(&mut h2); - println!("{}", h1.finish()); - println!("{}", h2.finish()); - println!("{:?}", template[0].syntax().text()); - println!("{:?}", template[1].syntax().text()); - println!("{}", template[0].syntax() == template[0].syntax()); - println!( - "{}", - template[0].syntax().green() == template[1].syntax().green() + assert_ne!( + h1.finish(), + h2.finish(), + "Templates with same syntax should have different hashes!" + ); + + // check template syntax (text & green node) + assert_eq!( + template[0].syntax().text(), + template[1].syntax().text(), + "The syntax (as text) of template 1 and 2 must be the same!" + ); + assert_eq!( + template[0].syntax().green(), + template[1].syntax().green(), + "The syntax (as green node) of template 1 and 2 must be the same!!" ); } + } + + #[test] + fn parser_test_2() { + let source = test_programs::PARSER_TEST_2; + + let syntax = SyntaxTreeBuilder::syntax_tree(source); + + if let Some(ast) = AstCircomProgram::cast(syntax) { + // print_ast_children(&ast); + + println!("Pragma: {:?}", ast.pragma().unwrap().syntax().text()); - // find token + print!("Templates: "); + let templates = ast.template_list(); + for template in templates.iter() { + // print!("{:?} ", template.name().unwrap().name().unwrap().syntax().text()); + print!("{:?} ", template.name().unwrap().syntax().text()); // leading whitespaces + // print!("{:?} ", template.syntax().text()); // leading whitespaces + } + println!(); + + print!("Functions: "); + let functions = ast.function_list(); + for function in functions.iter() { + print!("{:?} ", function.function_name().unwrap().syntax().text()); + // leading whitespaces + // print!("{:?} ", function.syntax().text()); // leading whitespaces + } + println!(); + } } #[test] - fn parser_test() { - let source = r#"/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . - */ - /* - - Binary Sum - ========== - - This component creates a binary sum componet of ops operands and n bits each operand. - - e is Number of carries: Depends on the number of operands in the input. - - Main Constraint: - in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1) + - + in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1) + - + .. - + in[ops-1][0] * 2^0 + in[ops-1][1] * 2^1 + ..... + in[ops-1][n-1] * 2^(n-1) + - === - out[0] * 2^0 + out[1] * 2^1 + + out[n+e-1] *2(n+e-1) - - To waranty binary outputs: - - out[0] * (out[0] - 1) === 0 - out[1] * (out[0] - 1) === 0 - . - . - . - out[n+e-1] * (out[n+e-1] - 1) == 0 - - */ - - - /* - This function calculates the number of extra bits in the output to do the full sum. - */ - pragma circom 2.0.0; - - function nbits(a) { - var n = 1; - var r = 0; - while (n-1> k) & 1; - - // Ensure out is binary - out[k] * (out[k] - 1) === 0; - - lout += out[k] * e2; - - e2 = e2+e2; + } + + #[test] + fn parser_test_5() { + let source = test_programs::PARSER_TEST_5; + + let syntax = SyntaxTreeBuilder::syntax_tree(source); + + if let Some(ast) = AstCircomProgram::cast(syntax) { + // print_ast_children(&ast); + + println!("{:?}", ast.pragma()); + // assert!(ast.pragma().is_none(), "No pragma in source code"); } - - // Ensure the sum; - - lin === lout; } - "#; - let _syntax = SyntaxTreeBuilder::syntax_tree(source); + #[test] + fn parser_test_6() { + let source = test_programs::PARSER_TEST_6; + + let syntax = SyntaxTreeBuilder::syntax_tree(source); + + if let Some(ast) = AstCircomProgram::cast(syntax) { + // print_ast_children(&ast); + + println!("{:?}", ast.pragma()); + // assert!(ast.pragma().is_none(), "No pragma in source code"); + } } } diff --git a/crates/syntax/src/test_programs.rs b/crates/syntax/src/test_programs.rs new file mode 100644 index 0000000..0879679 --- /dev/null +++ b/crates/syntax/src/test_programs.rs @@ -0,0 +1,135 @@ +pub const PARSER_TEST_1: &str = r#"pragma circom 2.0.0; + + + template Multiplier2 () {} + template Multiplier2 () {} + "#; + +pub const PARSER_TEST_2: &str = r#"/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +/* + +Binary Sum +========== + +This component creates a binary sum componet of ops operands and n bits each operand. + +e is Number of carries: Depends on the number of operands in the input. + +Main Constraint: + in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1) + + + in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1) + + + .. + + in[ops-1][0] * 2^0 + in[ops-1][1] * 2^1 + ..... + in[ops-1][n-1] * 2^(n-1) + + === + out[0] * 2^0 + out[1] * 2^1 + + out[n+e-1] *2(n+e-1) + +To waranty binary outputs: + + out[0] * (out[0] - 1) === 0 + out[1] * (out[0] - 1) === 0 + . + . + . + out[n+e-1] * (out[n+e-1] - 1) == 0 + + */ + + +/* + This function calculates the number of extra bits in the output to do the full sum. + */ + pragma circom 2.0.0; + +function nbits(a) { + var n = 1; + var r = 0; + while (n-1> k) & 1; + + // Ensure out is binary + out[k] * (out[k] - 1) === 0; + + lout += out[k] * e2; + + e2 = e2+e2; + } + + // Ensure the sum; + + lin === lout; + } + "#; + +pub const PARSER_TEST_3: &str = r#" + +// comment :> + + pragma circom 2.0.0; + + "#; + +pub const PARSER_TEST_4: &str = r#" + +/* +comment +blocks +*/ +pragma circom 2.0.0; + "#; + +pub const PARSER_TEST_5: &str = r#" +// no pragma here + template Multiplier2 () {} + "#; + +pub const PARSER_TEST_6: &str = r#" +/* T _ T */ + template Multiplier2 () {} + "#; + \ No newline at end of file From 6913c55cf23105829d5cf8f4b956f38775d17546 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Wed, 13 Nov 2024 13:20:34 +0700 Subject: [PATCH 02/59] remove comment in input test --- crates/parser/src/input.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index c8e17c8..cdfd5d8 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -120,10 +120,5 @@ mod tests { let input = Input::new(&source); assert_eq!(expected_input, input, "Tokens extract from source code are not correct"); - - // for i in 0..min(input.size(), 10) { - // println!("kind = {:?}", input.kind[i]); - // println!("position {:?}", input.position[i]); - // } } } From caac481857e878c4dd3113c2ca2e8c1d345d1dd7 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 18 Nov 2024 19:55:59 +0700 Subject: [PATCH 03/59] manage out-of-bound case, update input test --- crates/parser/src/input.rs | 297 +++++++++++++++++++++---------------- 1 file changed, 173 insertions(+), 124 deletions(-) diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index cdfd5d8..bb37613 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -1,124 +1,173 @@ -use std::ops::Range; - -use logos::Lexer; - -use crate::token_kind::TokenKind; - -#[derive(Debug, PartialEq)] -pub struct Input<'a> { - kind: Vec, - source: &'a str, - position: Vec>, -} - -impl<'a> Input<'a> { - pub fn new(source: &'a str) -> Self { - let mut input = Input { - source, - kind: Vec::new(), - position: Vec::new(), - }; - - let mut lex = Lexer::::new(source); - - while let Some(tk) = lex.next() { - if tk == TokenKind::CommentBlockOpen { - let mut closed = false; - let mut join_span = lex.span(); - while let Some(t) = lex.next() { - join_span.end = lex.span().end; - if t == TokenKind::CommentBlockClose { - closed = true; - break; - } - } - - if closed { - input.kind.push(TokenKind::BlockComment); - } else { - input.kind.push(TokenKind::Error); - } - input.position.push(join_span); - } else { - input.kind.push(tk); - input.position.push(lex.span()); - } - } - - input - } - - pub fn token_value(&self, index: usize) -> &'a str { - &self.source[self.position[index].start..self.position[index].end] - } - - pub fn kind_of(&self, index: usize) -> TokenKind { - if index < self.kind.len() { - self.kind[index] - } else { - TokenKind::EOF - } - } - - pub fn position_of(&self, index: usize) -> Range { - self.position[index].clone() - } - - pub fn size(&self) -> usize { - self.kind.len() - } -} - -#[cfg(test)] -mod tests { - // use std::cmp::min; - - use crate::token_kind::TokenKind; - - use super::Input; - - #[test] - fn test_input() { - let source = r#" - /*a + b == 10*/ - a + 10 - "# - .to_string(); - - let expected_input = Input { - kind: vec![ - TokenKind::EndLine, - TokenKind::WhiteSpace, - TokenKind::BlockComment, - TokenKind::EndLine, - TokenKind::WhiteSpace, - TokenKind::Identifier, - TokenKind::WhiteSpace, - TokenKind::Add, - TokenKind::WhiteSpace, - TokenKind::Number, - TokenKind::EndLine, - TokenKind::WhiteSpace - ], - source: &source, - position: vec![ - {0..1}, - {1..9}, - {9..24}, - {24..25}, - {25..33}, - {33..34}, - {34..35}, - {35..36}, - {36..37}, - {37..39}, - {39..40}, - {40..44}, - ] - }; - - let input = Input::new(&source); - - assert_eq!(expected_input, input, "Tokens extract from source code are not correct"); - } -} +use std::ops::Range; + +use logos::Lexer; + +use crate::token_kind::TokenKind; + +#[derive(Debug, PartialEq)] +pub struct Input<'a> { + kind: Vec, + source: &'a str, + position: Vec>, +} + +impl<'a> Input<'a> { + pub fn new(source: &'a str) -> Self { + let mut input = Input { + source, + kind: Vec::new(), + position: Vec::new(), + }; + + let mut lex = Lexer::::new(source); + + while let Some(tk) = lex.next() { + if tk == TokenKind::CommentBlockOpen { + let mut closed = false; + let mut join_span = lex.span(); + while let Some(t) = lex.next() { + join_span.end = lex.span().end; + if t == TokenKind::CommentBlockClose { + closed = true; + break; + } + } + + if closed { + input.kind.push(TokenKind::BlockComment); + } else { + input.kind.push(TokenKind::Error); + } + input.position.push(join_span); + } else { + input.kind.push(tk); + input.position.push(lex.span()); + } + } + + input + } + + pub fn token_value(&self, index: usize) -> &'a str { + if index < self.kind.len() { + &self.source[self.position[index].start..self.position[index].end] + } else { + // return error for out of bound index + "" + } + } + + pub fn kind_of(&self, index: usize) -> TokenKind { + if index < self.kind.len() { + self.kind[index] + } else { + TokenKind::EOF + } + } + + pub fn position_of(&self, index: usize) -> Range { + if index < self.kind.len() { + self.position[index].clone() + } else { + // return error for out of bound index + 0..0 + } + + } + + pub fn size(&self) -> usize { + self.kind.len() + } +} + +#[cfg(test)] +mod tests { + use crate::token_kind::TokenKind; + + use super::Input; + + #[test] + fn test_input() { + let source = r#" + /*a + b == 10*/ + a + 10 + "# + .to_string(); + + let expected_input = Input { + kind: vec![ + TokenKind::EndLine, + TokenKind::WhiteSpace, + TokenKind::BlockComment, + TokenKind::EndLine, + TokenKind::WhiteSpace, + TokenKind::Identifier, + TokenKind::WhiteSpace, + TokenKind::Add, + TokenKind::WhiteSpace, + TokenKind::Number, + TokenKind::EndLine, + TokenKind::WhiteSpace + ], + source: &source, + position: vec![ + {0..1}, + {1..9}, + {9..24}, + {24..25}, + {25..33}, + {33..34}, + {34..35}, + {35..36}, + {36..37}, + {37..39}, + {39..40}, + {40..44}, + ] + }; + + let input = Input::new(&source); + + assert_eq!(expected_input, input, "Tokens extract from source code are not correct"); + + // test size method + let expected_size = input.kind.len(); + let size = input.size(); + assert_eq!(expected_size, size, "size method failed"); + + // test methods with index out of bound + let index = input.kind.len(); + + let expected_token_value = ""; + let token_value = input.token_value(index); + assert_eq!(expected_token_value, token_value, "token_value failed (case: index out of bound)"); + + let expected_kind = TokenKind::EOF; + let kind = input.kind_of(index); + assert_eq!(expected_kind, kind, "kind_of failed (case: index out of bound)"); + + let expected_position = 0..0; + let position = input.position_of(index); + assert_eq!(expected_position, position, "position_of failed (case: index out of bound)"); + + // test methods with index in bound + if input.size() == 0 { + return; + } + + let index = input.size() / 2; // a valid index if input size > 0 + + let expected_token_value = &input.source[input.position[index].clone()]; + let token_value = input.token_value(index); + assert_eq!(expected_token_value, token_value, "token_value failed"); + + let expected_kind = input.kind[index]; + let kind = input.kind_of(index); + assert_eq!(expected_kind, kind, "kind_of failed"); + + let expected_position = input.position[index].clone(); + let position = input.position_of(index); + assert_eq!(expected_position, position, "position_of failed"); + + } +} From 8efa4f70d57a52e24b92ed4c5002ec339ed77095 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 18 Nov 2024 21:30:38 +0700 Subject: [PATCH 04/59] update input test --- crates/parser/src/input.rs | 145 +++++++++++++++++++++++++++++++------ 1 file changed, 123 insertions(+), 22 deletions(-) diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index bb37613..ebc1b9e 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -72,7 +72,6 @@ impl<'a> Input<'a> { // return error for out of bound index 0..0 } - } pub fn size(&self) -> usize { @@ -87,7 +86,7 @@ mod tests { use super::Input; #[test] - fn test_input() { + fn test_input_1() { let source = r#" /*a + b == 10*/ a + 10 @@ -107,27 +106,121 @@ mod tests { TokenKind::WhiteSpace, TokenKind::Number, TokenKind::EndLine, - TokenKind::WhiteSpace + TokenKind::WhiteSpace, ], source: &source, position: vec![ - {0..1}, - {1..9}, - {9..24}, - {24..25}, - {25..33}, - {33..34}, - {34..35}, - {35..36}, - {36..37}, - {37..39}, - {39..40}, - {40..44}, - ] + { 0..1 }, + { 1..9 }, + { 9..24 }, + { 24..25 }, + { 25..33 }, + { 33..34 }, + { 34..35 }, + { 35..36 }, + { 36..37 }, + { 37..39 }, + { 39..40 }, + { 40..44 }, + ], }; let input = Input::new(&source); + assert_eq!( + expected_input, input, + "Tokens extract from source code are not correct" + ); + + // test size method + let expected_size = input.kind.len(); + let size = input.size(); + assert_eq!(expected_size, size, "size method failed"); + + // test methods with index out of bound + let index = input.kind.len(); + + let expected_token_value = ""; + let token_value = input.token_value(index); + assert_eq!( + expected_token_value, token_value, + "token_value failed (case: index out of bound)" + ); + + let expected_kind = TokenKind::EOF; + let kind = input.kind_of(index); + assert_eq!( + expected_kind, kind, + "kind_of failed (case: index out of bound)" + ); + + let expected_position = 0..0; + let position = input.position_of(index); + assert_eq!( + expected_position, position, + "position_of failed (case: index out of bound)" + ); + + // test methods with index in bound + if input.size() == 0 { + return; + } + + let index = input.size() / 2; // a valid index if input size > 0 + + let expected_token_value = &input.source[input.position[index].clone()]; + let token_value = input.token_value(index); + assert_eq!(expected_token_value, token_value, "token_value failed"); + + let expected_kind = input.kind[index]; + let kind = input.kind_of(index); + assert_eq!(expected_kind, kind, "kind_of failed"); + + let expected_position = input.position[index].clone(); + let position = input.position_of(index); + assert_eq!(expected_position, position, "position_of failed"); + } + + #[test] + fn test_input_2() { + let source = r#" + pragma 2.1.1; + /*a + b == 10* + a + 10 + template + + /* + "# + .to_string(); + + let expected_input = Input { + kind: vec![ + TokenKind::EndLine, + TokenKind::WhiteSpace, + TokenKind::Pragma, + TokenKind::WhiteSpace, + TokenKind::Version, + TokenKind::Semicolon, + TokenKind::EndLine, + TokenKind::WhiteSpace, + TokenKind::Error, + ], + source: &source, + position: vec![ + 0..1, + 1..9, + 9..15, + 15..16, + 16..21, + 21..22, + 22..23, + 23..31, + 31..94, + ], + }; + + let input = Input::new(&source); + assert_eq!(expected_input, input, "Tokens extract from source code are not correct"); // test size method @@ -140,15 +233,24 @@ mod tests { let expected_token_value = ""; let token_value = input.token_value(index); - assert_eq!(expected_token_value, token_value, "token_value failed (case: index out of bound)"); + assert_eq!( + expected_token_value, token_value, + "token_value failed (case: index out of bound)" + ); let expected_kind = TokenKind::EOF; let kind = input.kind_of(index); - assert_eq!(expected_kind, kind, "kind_of failed (case: index out of bound)"); + assert_eq!( + expected_kind, kind, + "kind_of failed (case: index out of bound)" + ); let expected_position = 0..0; let position = input.position_of(index); - assert_eq!(expected_position, position, "position_of failed (case: index out of bound)"); + assert_eq!( + expected_position, position, + "position_of failed (case: index out of bound)" + ); // test methods with index in bound if input.size() == 0 { @@ -156,7 +258,7 @@ mod tests { } let index = input.size() / 2; // a valid index if input size > 0 - + let expected_token_value = &input.source[input.position[index].clone()]; let token_value = input.token_value(index); assert_eq!(expected_token_value, token_value, "token_value failed"); @@ -164,10 +266,9 @@ mod tests { let expected_kind = input.kind[index]; let kind = input.kind_of(index); assert_eq!(expected_kind, kind, "kind_of failed"); - + let expected_position = input.position[index].clone(); let position = input.position_of(index); assert_eq!(expected_position, position, "position_of failed"); - } } From c78761e2ae8378241608491964f93f81ac160b9b Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Fri, 6 Dec 2024 21:25:09 +0700 Subject: [PATCH 05/59] update input test --- crates/parser/src/input.rs | 285 ++++++++++++++++++++++---------- crates/parser/src/token_kind.rs | 3 + crates/syntax/src/syntax.rs | 12 +- 3 files changed, 209 insertions(+), 91 deletions(-) diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index ebc1b9e..4b1cc55 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -81,50 +81,11 @@ impl<'a> Input<'a> { #[cfg(test)] mod tests { - use crate::token_kind::TokenKind; + use crate::token_kind::TokenKind::{self, *}; use super::Input; - #[test] - fn test_input_1() { - let source = r#" - /*a + b == 10*/ - a + 10 - "# - .to_string(); - - let expected_input = Input { - kind: vec![ - TokenKind::EndLine, - TokenKind::WhiteSpace, - TokenKind::BlockComment, - TokenKind::EndLine, - TokenKind::WhiteSpace, - TokenKind::Identifier, - TokenKind::WhiteSpace, - TokenKind::Add, - TokenKind::WhiteSpace, - TokenKind::Number, - TokenKind::EndLine, - TokenKind::WhiteSpace, - ], - source: &source, - position: vec![ - { 0..1 }, - { 1..9 }, - { 9..24 }, - { 24..25 }, - { 25..33 }, - { 33..34 }, - { 34..35 }, - { 35..36 }, - { 36..37 }, - { 37..39 }, - { 39..40 }, - { 40..44 }, - ], - }; - + fn test(source: &str, expected_input: Input) { let input = Input::new(&source); assert_eq!( @@ -182,7 +143,49 @@ mod tests { } #[test] - fn test_input_2() { + fn test_comment_block() { + let source = r#" + /*a + b == 10*/ + a + 10 + "#; + + let expected_input = Input { + kind: vec![ + TokenKind::EndLine, + TokenKind::WhiteSpace, + TokenKind::BlockComment, + TokenKind::EndLine, + TokenKind::WhiteSpace, + TokenKind::Identifier, + TokenKind::WhiteSpace, + TokenKind::Add, + TokenKind::WhiteSpace, + TokenKind::Number, + TokenKind::EndLine, + TokenKind::WhiteSpace, + ], + source: &source, + position: vec![ + { 0..1 }, + { 1..9 }, + { 9..24 }, + { 24..25 }, + { 25..33 }, + { 33..34 }, + { 34..35 }, + { 35..36 }, + { 36..37 }, + { 37..39 }, + { 39..40 }, + { 40..44 }, + ], + }; + + test(source, expected_input); + } + + #[test] + fn test_comment_error() { let source = r#" pragma 2.1.1; /*a + b == 10* @@ -190,8 +193,7 @@ mod tests { template /* - "# - .to_string(); + "#; let expected_input = Input { kind: vec![ @@ -219,56 +221,169 @@ mod tests { ], }; - let input = Input::new(&source); + test(source, expected_input); + } - assert_eq!(expected_input, input, "Tokens extract from source code are not correct"); + #[test] + fn test_pragma() { + let source = r#" + /* test pragma token kinds */ - // test size method - let expected_size = input.kind.len(); - let size = input.size(); - assert_eq!(expected_size, size, "size method failed"); + pragma circom 2.0.0; - // test methods with index out of bound - let index = input.kind.len(); + "#; - let expected_token_value = ""; - let token_value = input.token_value(index); - assert_eq!( - expected_token_value, token_value, - "token_value failed (case: index out of bound)" - ); - - let expected_kind = TokenKind::EOF; - let kind = input.kind_of(index); - assert_eq!( - expected_kind, kind, - "kind_of failed (case: index out of bound)" - ); + let expected_input = Input { + kind: vec![ + EndLine, + WhiteSpace, + BlockComment, + EndLine, + EndLine, + WhiteSpace, + Pragma, + WhiteSpace, + Circom, + WhiteSpace, + Version, + Semicolon, + EndLine, + EndLine, + WhiteSpace, + ], + source: &source, + position: vec![ + 0..1, + 1..9, + 9..38, + 38..39, + 39..40, + 40..44, + 44..50, + 50..51, + 51..57, + 57..58, + 58..63, + 63..64, + 64..65, + 65..66, + 66..70, + ], + }; - let expected_position = 0..0; - let position = input.position_of(index); - assert_eq!( - expected_position, position, - "position_of failed (case: index out of bound)" - ); + test(source, expected_input); + } - // test methods with index in bound - if input.size() == 0 { - return; + #[test] + fn test_function() { + let source = r#" + function nbits(a) { + var n = 1; + var r = 0; + while (n-1 0 + let expected_input = Input { + kind: vec![ + EndLine, WhiteSpace, FunctionKw, WhiteSpace, Identifier, LParen, Identifier, + RParen, WhiteSpace, LCurly, EndLine, WhiteSpace, VarKw, WhiteSpace, Identifier, + WhiteSpace, Assign, WhiteSpace, Number, Semicolon, EndLine, WhiteSpace, VarKw, + WhiteSpace, Identifier, WhiteSpace, Assign, WhiteSpace, Number, Semicolon, EndLine, + WhiteSpace, WhileKw, WhiteSpace, LParen, Identifier, Sub, Number, LessThan, + Identifier, RParen, WhiteSpace, LCurly, EndLine, WhiteSpace, Identifier, Add, Add, + Semicolon, EndLine, WhiteSpace, Identifier, WhiteSpace, Mul, Assign, WhiteSpace, + Number, Semicolon, EndLine, WhiteSpace, RCurly, EndLine, WhiteSpace, ReturnKw, + WhiteSpace, Identifier, Semicolon, EndLine, WhiteSpace, RCurly, + ], + source: &source, + position: vec![ + 0..1, + 1..5, + 5..13, + 13..14, + 14..19, + 19..20, + 20..21, + 21..22, + 22..23, + 23..24, + 24..25, + 25..33, + 33..36, + 36..37, + 37..38, + 38..39, + 39..40, + 40..41, + 41..42, + 42..43, + 43..44, + 44..52, + 52..55, + 55..56, + 56..57, + 57..58, + 58..59, + 59..60, + 60..61, + 61..62, + 62..63, + 63..71, + 71..76, + 76..77, + 77..78, + 78..79, + 79..80, + 80..81, + 81..82, + 82..83, + 83..84, + 84..85, + 85..86, + 86..87, + 87..99, + 99..100, + 100..101, + 101..102, + 102..103, + 103..104, + 104..116, + 116..117, + 117..118, + 118..119, + 119..120, + 120..121, + 121..122, + 122..123, + 123..124, + 124..132, + 132..133, + 133..134, + 134..142, + 142..148, + 148..149, + 149..150, + 150..151, + 151..152, + 152..156, + 156..157, + ], + }; - let expected_token_value = &input.source[input.position[index].clone()]; - let token_value = input.token_value(index); - assert_eq!(expected_token_value, token_value, "token_value failed"); + test(source, expected_input); + } - let expected_kind = input.kind[index]; - let kind = input.kind_of(index); - assert_eq!(expected_kind, kind, "kind_of failed"); + // #[test] + // fn test_gen() { + // let source = r#" + // "#; - let expected_position = input.position[index].clone(); - let position = input.position_of(index); - assert_eq!(expected_position, position, "position_of failed"); - } + // let input = Input::new(&source); + // println!("{:?}", input.kind); + // println!("{:?}", input.position); + // } } diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 26145bf..779191f 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -229,6 +229,7 @@ impl TokenKind { _ => None, } } + pub fn prefix(self) -> Option { match self { Self::Sub => Some(100), @@ -245,9 +246,11 @@ impl TokenKind { _ => None, } } + pub fn is_declaration_kw(self) -> bool { matches!(self, Self::VarKw | Self::ComponentKw | Self::SignalKw) } + pub fn is_trivial(self) -> bool { matches!( self, diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 3483b61..21b9734 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -126,7 +126,7 @@ mod tests { } #[test] - fn parser_test_1() { + fn syntax_test_1() { let source: &str = test_programs::PARSER_TEST_1; let expected_pragma = "pragma circom 2.0.0;".to_string(); @@ -206,7 +206,7 @@ mod tests { } #[test] - fn parser_test_2() { + fn syntax_test_2() { let source = test_programs::PARSER_TEST_2; let syntax = SyntaxTreeBuilder::syntax_tree(source); @@ -237,7 +237,7 @@ mod tests { } #[test] - fn parser_test_3() { + fn syntax_test_3() { let source = test_programs::PARSER_TEST_3; let syntax = SyntaxTreeBuilder::syntax_tree(source); @@ -254,7 +254,7 @@ mod tests { } #[test] - fn parser_test_4() { + fn syntax_test_4() { let source = test_programs::PARSER_TEST_4; let syntax = SyntaxTreeBuilder::syntax_tree(source); @@ -271,7 +271,7 @@ mod tests { } #[test] - fn parser_test_5() { + fn syntax_test_5() { let source = test_programs::PARSER_TEST_5; let syntax = SyntaxTreeBuilder::syntax_tree(source); @@ -285,7 +285,7 @@ mod tests { } #[test] - fn parser_test_6() { + fn syntax_test_6() { let source = test_programs::PARSER_TEST_6; let syntax = SyntaxTreeBuilder::syntax_tree(source); From bfd1f1519bba52be08a0b9032bdaa28edad5dff5 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sun, 8 Dec 2024 15:38:34 +0700 Subject: [PATCH 06/59] make test programs private --- crates/syntax/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index adeb8b0..d1300bb 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -3,4 +3,4 @@ pub mod syntax_node; pub mod abstract_syntax_tree; -pub mod test_programs; \ No newline at end of file +mod test_programs; \ No newline at end of file From e054b574fa54e0862006da06e0072a11789aa780 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sun, 8 Dec 2024 15:41:47 +0700 Subject: [PATCH 07/59] remove comments in syntax tests --- crates/syntax/src/syntax.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 21b9734..58d7194 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -277,9 +277,8 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - // print_ast_children(&ast); - - println!("{:?}", ast.pragma()); + println!("pragma: {:?}", ast.pragma()); + println!("template list: {:?}", ast.template_list()); // assert!(ast.pragma().is_none(), "No pragma in source code"); } } @@ -294,6 +293,8 @@ mod tests { // print_ast_children(&ast); println!("{:?}", ast.pragma()); + + println!("template list: {:?}", ast.template_list()); // assert!(ast.pragma().is_none(), "No pragma in source code"); } } From 15c9e5f7dfb801952f358f8e2d97036cb7928a67 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sun, 8 Dec 2024 15:45:28 +0700 Subject: [PATCH 08/59] format --- crates/parser/src/grammar.rs | 5 +++-- crates/parser/src/grammar/block.rs | 1 + crates/parser/src/grammar/declaration.rs | 3 +++ crates/parser/src/grammar/expression.rs | 1 + crates/parser/src/grammar/function.rs | 8 +++++--- crates/parser/src/grammar/include.rs | 2 +- crates/parser/src/grammar/list_identity.rs | 1 + crates/parser/src/grammar/main_component.rs | 7 +++++++ crates/parser/src/grammar/template.rs | 2 +- crates/parser/src/output.rs | 1 + crates/parser/src/token_kind.rs | 2 +- crates/syntax/src/syntax.rs | 10 ---------- 12 files changed, 25 insertions(+), 18 deletions(-) diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 98832cc..6b3791a 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -35,14 +35,15 @@ pub mod entry { } pragma::pragma(p); + while !p.eof() { match p.current() { TemplateKw => { template::template(p); - } + }, IncludeKw => { include::include(p); - } + }, ComponentKw => main_component::main_component(p), FunctionKw => function::function_parse(p), _ => { diff --git a/crates/parser/src/grammar/block.rs b/crates/parser/src/grammar/block.rs index 7b0f89a..5a40865 100644 --- a/crates/parser/src/grammar/block.rs +++ b/crates/parser/src/grammar/block.rs @@ -2,6 +2,7 @@ use super::*; pub fn block(p: &mut Parser) { p.inc_rcurly(); + if !p.at(LCurly) { p.advance_with_error("Miss {"); } else { diff --git a/crates/parser/src/grammar/declaration.rs b/crates/parser/src/grammar/declaration.rs index 1ebbb70..8022f81 100644 --- a/crates/parser/src/grammar/declaration.rs +++ b/crates/parser/src/grammar/declaration.rs @@ -3,6 +3,9 @@ use super::{ *, }; +// "signal" --> None +// "signal input" --> Some(true) +// "signal output" --> Some(false) fn signal_header(p: &mut Parser) -> Option { let mut res = None; let m = p.open(); diff --git a/crates/parser/src/grammar/expression.rs b/crates/parser/src/grammar/expression.rs index 8932828..8c7fad6 100644 --- a/crates/parser/src/grammar/expression.rs +++ b/crates/parser/src/grammar/expression.rs @@ -1,6 +1,7 @@ use crate::parser::Marker; use super::*; + pub(super) fn expression(p: &mut Parser) { let m = p.open(); circom_expression(p); diff --git a/crates/parser/src/grammar/function.rs b/crates/parser/src/grammar/function.rs index 24b60d3..fad1d44 100644 --- a/crates/parser/src/grammar/function.rs +++ b/crates/parser/src/grammar/function.rs @@ -1,12 +1,15 @@ use crate::grammar::*; +// fucntion name() pub fn function_parse(p: &mut Parser) { let m = p.open(); + p.expect(FunctionKw); - let fn_name_marker = p.open(); + let fn_name_marker = p.open(); p.expect(Identifier); p.close(fn_name_marker, FunctionName); + p.expect(LParen); let arg_marker = p.open(); while !p.at(RParen) && !p.eof() { @@ -15,11 +18,10 @@ pub fn function_parse(p: &mut Parser) { p.expect(Comma); } } - p.close(arg_marker, ParameterList); - p.expect(RParen); block::block(p); + p.close(m, FunctionDef); } diff --git a/crates/parser/src/grammar/include.rs b/crates/parser/src/grammar/include.rs index 7269995..d8f0ac7 100644 --- a/crates/parser/src/grammar/include.rs +++ b/crates/parser/src/grammar/include.rs @@ -2,7 +2,7 @@ use super::*; pub(super) fn include(p: &mut Parser) { // assert!(p.at(IncludeKw)); - + let m = p.open(); p.expect(IncludeKw); p.expect(CircomString); diff --git a/crates/parser/src/grammar/list_identity.rs b/crates/parser/src/grammar/list_identity.rs index 6a4effa..73f85c9 100644 --- a/crates/parser/src/grammar/list_identity.rs +++ b/crates/parser/src/grammar/list_identity.rs @@ -1,5 +1,6 @@ use super::*; +// a, b, c, d pub fn parse(p: &mut Parser) { while p.at(Identifier) && !p.eof() { p.expect(Identifier); diff --git a/crates/parser/src/grammar/main_component.rs b/crates/parser/src/grammar/main_component.rs index 538a73b..3f6f862 100644 --- a/crates/parser/src/grammar/main_component.rs +++ b/crates/parser/src/grammar/main_component.rs @@ -1,13 +1,20 @@ use super::*; +/* +component main {public [signal_list]} = tempid(v1,...,vn); + +{public [signal_list]} is optional +*/ pub fn main_component(p: &mut Parser) { p.expect(ComponentKw); p.expect(MainKw); + p.expect(LCurly); p.expect(PublicKw); p.expect(LBracket); list_identity::parse(p); p.expect(RBracket); + p.expect(Assign); expression::expression(p); } diff --git a/crates/parser/src/grammar/template.rs b/crates/parser/src/grammar/template.rs index 9973366..9249b1f 100644 --- a/crates/parser/src/grammar/template.rs +++ b/crates/parser/src/grammar/template.rs @@ -1,7 +1,7 @@ use crate::grammar::*; /** * template Identifier() {content} - * + * template Identifier( param_1, ... , param_n ) { content } */ pub fn template(p: &mut Parser) { // assert!(p.at(TemplateKw)); diff --git a/crates/parser/src/output.rs b/crates/parser/src/output.rs index 0a4e07d..271c2c3 100644 --- a/crates/parser/src/output.rs +++ b/crates/parser/src/output.rs @@ -30,6 +30,7 @@ impl Output { &self.children } } + impl From> for Output { fn from(events: Vec) -> Self { let mut stack = Vec::new(); diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 779191f..9ebba15 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -229,7 +229,7 @@ impl TokenKind { _ => None, } } - + pub fn prefix(self) -> Option { match self { Self::Sub => Some(100), diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 58d7194..f44b88c 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -212,14 +212,11 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - // print_ast_children(&ast); - println!("Pragma: {:?}", ast.pragma().unwrap().syntax().text()); print!("Templates: "); let templates = ast.template_list(); for template in templates.iter() { - // print!("{:?} ", template.name().unwrap().name().unwrap().syntax().text()); print!("{:?} ", template.name().unwrap().syntax().text()); // leading whitespaces // print!("{:?} ", template.syntax().text()); // leading whitespaces } @@ -243,8 +240,6 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - // print_ast_children(&ast); - println!("Pragma: {:?}", ast.pragma().unwrap().syntax().text()); println!( "Pragma version: {:?}", @@ -260,8 +255,6 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - // print_ast_children(&ast); - println!("Pragma: {:?}", ast.pragma().unwrap().syntax().text()); println!( "Pragma version: {:?}", @@ -290,10 +283,7 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - // print_ast_children(&ast); - println!("{:?}", ast.pragma()); - println!("template list: {:?}", ast.template_list()); // assert!(ast.pragma().is_none(), "No pragma in source code"); } From c76246b5251954ffb6e31f34294754eb5efcd327 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sun, 8 Dec 2024 16:04:32 +0700 Subject: [PATCH 09/59] make Pragma optional, remove ROOT --- crates/parser/src/grammar.rs | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 6b3791a..a0c9f53 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -34,21 +34,14 @@ pub mod entry { p.skip(); } - pragma::pragma(p); - while !p.eof() { match p.current() { - TemplateKw => { - template::template(p); - }, - IncludeKw => { - include::include(p); - }, + Pragma => pragma::pragma(p), + TemplateKw => template::template(p), + IncludeKw => include::include(p), ComponentKw => main_component::main_component(p), FunctionKw => function::function_parse(p), - _ => { - p.advance_with_error("invalid token"); - } + _ => p.advance_with_error("invalid token"), } } p.close(m, CircomProgram); @@ -64,20 +57,10 @@ pub mod entry { impl Scope { pub fn parse(self, p: &mut Parser) { match self { - Self::Block => { - let m = p.open(); - block::block(p); - p.close(m, ROOT); - } + Self::Block => block::block(p), Self::CircomProgram => circom_program(p), - Self::Pragma => { - let m = p.open(); - pragma::pragma(p); - p.close(m, ROOT); - } - Self::Template => { - template::template(p); - } + Self::Pragma => pragma::pragma(p), + Self::Template => template::template(p), } } } From cd125abe3dee9663b84f010eeeff6775c10b08a9 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sun, 8 Dec 2024 16:07:16 +0700 Subject: [PATCH 10/59] rename close() params, use advance() in eat(), fix typo scope --- crates/parser/src/parser.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index 23c4dde..a4f0efe 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -52,8 +52,8 @@ impl<'a> Parser<'a> { } } - pub fn close(&mut self, marker_close: Marker, kind: TokenKind) -> Marker { - match marker_close { + pub fn close(&mut self, marker_open: Marker, kind: TokenKind) -> Marker { + match marker_open { Marker::Open(index) => { self.events[index] = Event::Open { kind }; self.events.push(Event::Close); @@ -159,8 +159,7 @@ impl<'a> Parser<'a> { pub fn eat(&mut self, kind: TokenKind) -> bool { if self.at(kind) { - self.events.push(Event::TokenPosition(self.pos)); - self.skip(); + self.advance(); return true; } false @@ -193,7 +192,7 @@ impl<'a> Parser<'a> { } impl Parser<'_> { - pub fn parsing_with_scrope(input: &Input, scope: Scope) -> Output { + pub fn parsing_with_scope(input: &Input, scope: Scope) -> Output { let mut p = Parser::new(input); scope.parse(&mut p); Output::from(p.events) @@ -201,6 +200,6 @@ impl Parser<'_> { pub fn parsing(input: &Input) -> Output { let c = Scope::CircomProgram; - Parser::parsing_with_scrope(input, c) + Parser::parsing_with_scope(input, c) } } From 15470b1035bf20a855ae0be0d83f74ed275e2311 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sun, 8 Dec 2024 16:08:12 +0700 Subject: [PATCH 11/59] parse params using list_identity --- crates/parser/src/grammar/function.rs | 7 +------ crates/parser/src/grammar/template.rs | 12 +++++------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/crates/parser/src/grammar/function.rs b/crates/parser/src/grammar/function.rs index fad1d44..bca7018 100644 --- a/crates/parser/src/grammar/function.rs +++ b/crates/parser/src/grammar/function.rs @@ -12,12 +12,7 @@ pub fn function_parse(p: &mut Parser) { p.expect(LParen); let arg_marker = p.open(); - while !p.at(RParen) && !p.eof() { - p.expect(Identifier); - if p.at(Comma) { - p.expect(Comma); - } - } + list_identity::parse(p); p.close(arg_marker, ParameterList); p.expect(RParen); diff --git a/crates/parser/src/grammar/template.rs b/crates/parser/src/grammar/template.rs index 9249b1f..be5f17e 100644 --- a/crates/parser/src/grammar/template.rs +++ b/crates/parser/src/grammar/template.rs @@ -6,23 +6,21 @@ use crate::grammar::*; pub fn template(p: &mut Parser) { // assert!(p.at(TemplateKw)); let m = p.open(); + p.expect(TemplateKw); + let name_marker = p.open(); p.expect(Identifier); p.close(name_marker, TemplateName); p.expect(LParen); let arg_marker = p.open(); - while !p.at(RParen) && !p.eof() { - p.expect(Identifier); - if p.at(Comma) { - p.expect(Comma); - } - } - + list_identity::parse(p); p.close(arg_marker, ParameterList); p.expect(RParen); + block::block(p); + p.close(m, TemplateDef); } From 6dbb51a333ccc075c49a609895bce1a32b5c7041 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 10 Dec 2024 22:40:00 +0700 Subject: [PATCH 12/59] return Option in token_value() and position_of() --- crates/parser/src/input.rs | 22 +++++++++++----------- crates/syntax/src/syntax.rs | 3 ++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index 4b1cc55..8ddf602 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -48,12 +48,12 @@ impl<'a> Input<'a> { input } - pub fn token_value(&self, index: usize) -> &'a str { + pub fn token_value(&self, index: usize) -> Option<&'a str> { if index < self.kind.len() { - &self.source[self.position[index].start..self.position[index].end] + Some(&self.source[self.position[index].start..self.position[index].end]) } else { - // return error for out of bound index - "" + // return None for out of bound index + None } } @@ -65,12 +65,12 @@ impl<'a> Input<'a> { } } - pub fn position_of(&self, index: usize) -> Range { + pub fn position_of(&self, index: usize) -> Option> { if index < self.kind.len() { - self.position[index].clone() + Some(self.position[index].clone()) } else { // return error for out of bound index - 0..0 + None } } @@ -101,7 +101,7 @@ mod tests { // test methods with index out of bound let index = input.kind.len(); - let expected_token_value = ""; + let expected_token_value = None; let token_value = input.token_value(index); assert_eq!( expected_token_value, token_value, @@ -115,7 +115,7 @@ mod tests { "kind_of failed (case: index out of bound)" ); - let expected_position = 0..0; + let expected_position = None; let position = input.position_of(index); assert_eq!( expected_position, position, @@ -130,7 +130,7 @@ mod tests { let index = input.size() / 2; // a valid index if input size > 0 let expected_token_value = &input.source[input.position[index].clone()]; - let token_value = input.token_value(index); + let token_value = input.token_value(index).unwrap(); assert_eq!(expected_token_value, token_value, "token_value failed"); let expected_kind = input.kind[index]; @@ -138,7 +138,7 @@ mod tests { assert_eq!(expected_kind, kind, "kind_of failed"); let expected_position = input.position[index].clone(); - let position = input.position_of(index); + let position = input.position_of(index).unwrap(); assert_eq!(expected_position, position, "position_of failed"); } diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index f44b88c..32a273b 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -23,7 +23,8 @@ impl<'a> SyntaxTreeBuilder<'a> { match child { Child::Token(token_id) => { let token_kind = self.input.kind_of(*token_id); - let token_value = self.input.token_value(*token_id); + // TODO: return Error to replace .unwrap() + let token_value = self.input.token_value(*token_id).unwrap(); self.builder.start_node(token_kind.into()); self.builder.token(token_kind.into(), token_value); self.builder.finish_node(); From 6d5f0c6d44d8d8d15e8bfa66b68659dc4644552a Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 10 Dec 2024 22:51:11 +0700 Subject: [PATCH 13/59] do not allow <--, <== in var declaration --- crates/parser/src/grammar/declaration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/parser/src/grammar/declaration.rs b/crates/parser/src/grammar/declaration.rs index 8022f81..c37630c 100644 --- a/crates/parser/src/grammar/declaration.rs +++ b/crates/parser/src/grammar/declaration.rs @@ -38,7 +38,7 @@ pub(super) fn var_declaration(p: &mut Parser) { if p.at(LParen) { tuple(p); - if p.at_any(&[Assign, RAssignSignal, RAssignConstraintSignal]) { + if p.at(Assign) { tuple_init(p); } } else { From fbdc5b9857cd6944c9b0df9cb892d44c00ece8dc Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 10 Dec 2024 22:54:53 +0700 Subject: [PATCH 14/59] make public signal optional in main component --- crates/parser/src/grammar/main_component.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/parser/src/grammar/main_component.rs b/crates/parser/src/grammar/main_component.rs index 3f6f862..d9c176d 100644 --- a/crates/parser/src/grammar/main_component.rs +++ b/crates/parser/src/grammar/main_component.rs @@ -9,11 +9,13 @@ pub fn main_component(p: &mut Parser) { p.expect(ComponentKw); p.expect(MainKw); - p.expect(LCurly); - p.expect(PublicKw); - p.expect(LBracket); - list_identity::parse(p); - p.expect(RBracket); + if p.at(LCurly) { + p.expect(LCurly); + p.expect(PublicKw); + p.expect(LBracket); + list_identity::parse(p); + p.expect(RBracket); + } p.expect(Assign); expression::expression(p); From 07c4171540a9fbb51df57caa9e2f09671b12b9f6 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Fri, 13 Dec 2024 14:32:06 +0700 Subject: [PATCH 15/59] fix format before merge --- crates/parser/src/grammar/block.rs | 2 +- crates/parser/src/grammar/function.rs | 2 +- crates/parser/src/grammar/include.rs | 2 +- crates/parser/src/grammar/main_component.rs | 2 +- crates/parser/src/grammar/template.rs | 2 +- crates/syntax/src/lib.rs | 5 ++--- crates/syntax/src/syntax.rs | 3 +-- crates/syntax/src/test_programs.rs | 1 - 8 files changed, 8 insertions(+), 11 deletions(-) diff --git a/crates/parser/src/grammar/block.rs b/crates/parser/src/grammar/block.rs index 5a40865..03f7ed2 100644 --- a/crates/parser/src/grammar/block.rs +++ b/crates/parser/src/grammar/block.rs @@ -2,7 +2,7 @@ use super::*; pub fn block(p: &mut Parser) { p.inc_rcurly(); - + if !p.at(LCurly) { p.advance_with_error("Miss {"); } else { diff --git a/crates/parser/src/grammar/function.rs b/crates/parser/src/grammar/function.rs index bca7018..4da6276 100644 --- a/crates/parser/src/grammar/function.rs +++ b/crates/parser/src/grammar/function.rs @@ -3,7 +3,7 @@ use crate::grammar::*; // fucntion name() pub fn function_parse(p: &mut Parser) { let m = p.open(); - + p.expect(FunctionKw); let fn_name_marker = p.open(); diff --git a/crates/parser/src/grammar/include.rs b/crates/parser/src/grammar/include.rs index d8f0ac7..7269995 100644 --- a/crates/parser/src/grammar/include.rs +++ b/crates/parser/src/grammar/include.rs @@ -2,7 +2,7 @@ use super::*; pub(super) fn include(p: &mut Parser) { // assert!(p.at(IncludeKw)); - + let m = p.open(); p.expect(IncludeKw); p.expect(CircomString); diff --git a/crates/parser/src/grammar/main_component.rs b/crates/parser/src/grammar/main_component.rs index d9c176d..5129310 100644 --- a/crates/parser/src/grammar/main_component.rs +++ b/crates/parser/src/grammar/main_component.rs @@ -8,7 +8,7 @@ component main {public [signal_list]} = tempid(v1,...,vn); pub fn main_component(p: &mut Parser) { p.expect(ComponentKw); p.expect(MainKw); - + if p.at(LCurly) { p.expect(LCurly); p.expect(PublicKw); diff --git a/crates/parser/src/grammar/template.rs b/crates/parser/src/grammar/template.rs index be5f17e..693fe68 100644 --- a/crates/parser/src/grammar/template.rs +++ b/crates/parser/src/grammar/template.rs @@ -8,7 +8,7 @@ pub fn template(p: &mut Parser) { let m = p.open(); p.expect(TemplateKw); - + let name_marker = p.open(); p.expect(Identifier); p.close(name_marker, TemplateName); diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index d1300bb..7f4b53c 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -1,6 +1,5 @@ +pub mod abstract_syntax_tree; pub mod syntax; pub mod syntax_node; -pub mod abstract_syntax_tree; - -mod test_programs; \ No newline at end of file +mod test_programs; diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 32a273b..9b9202f 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -164,8 +164,7 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); - - if let Some(ast) = AstCircomProgram::cast(syntax) { + if let Some(ast) = AstCircomProgram::cast(syntax) { check_ast_children(&ast, &expected_kinds, &expected_ranges); // check pragma diff --git a/crates/syntax/src/test_programs.rs b/crates/syntax/src/test_programs.rs index 0879679..655222f 100644 --- a/crates/syntax/src/test_programs.rs +++ b/crates/syntax/src/test_programs.rs @@ -132,4 +132,3 @@ pub const PARSER_TEST_6: &str = r#" /* T _ T */ template Multiplier2 () {} "#; - \ No newline at end of file From 0bf3a04a0f476adf43cda2d39136b01592ab9bf1 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 17 Dec 2024 15:59:27 +0700 Subject: [PATCH 16/59] remove empty test --- crates/parser/src/grammar/declaration.rs | 8 +---- crates/parser/src/grammar/expression.rs | 24 +------------ crates/parser/src/grammar/pragma.rs | 23 ------------ crates/parser/src/grammar/statement.rs | 46 ++++++++++++++---------- crates/parser/src/grammar/template.rs | 41 +-------------------- 5 files changed, 31 insertions(+), 111 deletions(-) diff --git a/crates/parser/src/grammar/declaration.rs b/crates/parser/src/grammar/declaration.rs index c37630c..27471b3 100644 --- a/crates/parser/src/grammar/declaration.rs +++ b/crates/parser/src/grammar/declaration.rs @@ -127,10 +127,4 @@ pub(super) fn declaration(p: &mut Parser) { ComponentKw => component_declaration(p), _ => unreachable!(), } -} - -#[cfg(test)] -mod declar_tests { - #[test] - fn signal_with_tag() {} -} +} \ No newline at end of file diff --git a/crates/parser/src/grammar/expression.rs b/crates/parser/src/grammar/expression.rs index 8c7fad6..96c85e0 100644 --- a/crates/parser/src/grammar/expression.rs +++ b/crates/parser/src/grammar/expression.rs @@ -155,26 +155,4 @@ fn circom_expression(p: &mut Parser) { p.close(m, TenaryConditional); } } -} -// #[cfg(test)] -// mod tests { - -// use rowan::SyntaxNode; - -// use crate::{syntax_node::CircomLang}; - -// use super::{entry::Scope, Parser}; - -// #[test] -// fn test_expression() { -// let source = r#" -// { -// a.tmp <== 100; -// b[1].c <== 10; -// } -// "#; -// let green = Parser::parse_scope(source, Scope::Block); -// let node = SyntaxNode::::new_root(green); -// println!("{:#?}", node); -// } -// } +} \ No newline at end of file diff --git a/crates/parser/src/grammar/pragma.rs b/crates/parser/src/grammar/pragma.rs index bacf839..9ce3eaf 100644 --- a/crates/parser/src/grammar/pragma.rs +++ b/crates/parser/src/grammar/pragma.rs @@ -14,26 +14,3 @@ pub fn pragma(p: &mut Parser) { p.expect(Semicolon); p.close(m, Pragma); } - -// #[cfg(test)] -// mod tests { -// #[test] -// fn pragam_test() { -// use crate::{ -// ast::{AstNode, AstPragma}, -// syntax_node::SyntaxNode, -// token_kind::TokenKind, -// }; - -// use super::{entry::Scope, Parser}; - -// let source: String = r#"pragma circom 2.0.1;"#.to_string(); - -// let green_node = Parser::parse_scope(&source, Scope::Pragma); -// let node = SyntaxNode::new_root(green_node); - -// let pragma = AstPragma::cast(node.last_child().unwrap()).unwrap(); - -// assert!(pragma.version().unwrap().syntax().kind() == TokenKind::Version); -// } -// } diff --git a/crates/parser/src/grammar/statement.rs b/crates/parser/src/grammar/statement.rs index a4ee698..d8b75fa 100644 --- a/crates/parser/src/grammar/statement.rs +++ b/crates/parser/src/grammar/statement.rs @@ -9,6 +9,12 @@ pub(super) fn statement(p: &mut Parser) { p.close(m, Statement); } +/* +if (expr) + +else + +*/ fn if_statement(p: &mut Parser) { let m = p.open(); p.expect(IfKw); @@ -25,6 +31,7 @@ fn if_statement(p: &mut Parser) { /** * no if condition here. + * for/while/return/assert... */ fn statement_no_condition(p: &mut Parser) { match p.current() { @@ -50,6 +57,10 @@ fn statement_no_condition(p: &mut Parser) { } } +/* +for (/; ; ) + +*/ fn for_statement(p: &mut Parser) { let m = p.open(); p.expect(ForKw); @@ -70,6 +81,10 @@ fn for_statement(p: &mut Parser) { p.close(m, ForLoop); } +/* +while () + +*/ fn while_statement(p: &mut Parser) { p.expect(WhileKw); p.expect(LParen); @@ -78,6 +93,9 @@ fn while_statement(p: &mut Parser) { statement(p); } +/* +assert() +*/ fn assert_statement(p: &mut Parser) { let m = p.open(); p.expect(AssertKw); @@ -87,6 +105,9 @@ fn assert_statement(p: &mut Parser) { p.close(m, AssertKw); } +/* +log() +*/ fn log_statement(p: &mut Parser) { let m = p.open(); p.expect(LogKw); @@ -109,6 +130,9 @@ fn log_statement(p: &mut Parser) { p.close(m, LogKw); } +/* +return +*/ fn return_statement(p: &mut Parser) { let m = p.open(); p.expect(ReturnKw); @@ -116,6 +140,9 @@ fn return_statement(p: &mut Parser) { p.close(m, ReturnKw); } +/* + +*/ fn assignment_statement(p: &mut Parser) { let m = p.open(); @@ -154,21 +181,4 @@ fn assignment_statement(p: &mut Parser) { } else { p.close(m, Error); } -} - -#[cfg(test)] -mod tests { - - #[test] - fn if_statement_test() { - let _source = r#" - assert(1 == 2); - "#; - // let mut parser = Parser::new(source); - - // statement(&mut parser); - // let cst = parser.build_tree().ok().unwrap(); - - // println!("{:?}", cst); - } -} +} \ No newline at end of file diff --git a/crates/parser/src/grammar/template.rs b/crates/parser/src/grammar/template.rs index 693fe68..359d774 100644 --- a/crates/parser/src/grammar/template.rs +++ b/crates/parser/src/grammar/template.rs @@ -22,43 +22,4 @@ pub fn template(p: &mut Parser) { block::block(p); p.close(m, TemplateDef); -} - -// #[cfg(test)] -// mod tests { -// use crate::ast::AstTemplateDef; - -// #[test] -// fn template_parse_test() { -// use crate::{ast::AstNode, syntax_node::SyntaxNode}; - -// use super::{entry::Scope, Parser}; - -// let source: String = r#" -// template Multiplier2 (a, b, c) { - -// // Declaration of signals. -// signal input a; -// signal input b; -// signal output c; - -// // Constraints. -// c <== a * b; -// } - -// "# -// .to_string(); - -// let green_node = ::parse_scope(&source, Scope::Template); -// let node = SyntaxNode::new_root(green_node); - -// let ast_template = AstTemplateDef::cast(node); - -// if let Some(ast_internal) = ast_template { -// println!( -// "name {:?}", -// ast_internal.template_name().unwrap().syntax().text() -// ); -// } -// } -// } +} \ No newline at end of file From f1b0c3967be3941287c76bb69b90a9290d9db586 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 17 Dec 2024 16:00:07 +0700 Subject: [PATCH 17/59] replace expect by eat in block --- crates/parser/src/grammar/block.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/parser/src/grammar/block.rs b/crates/parser/src/grammar/block.rs index 03f7ed2..f01b515 100644 --- a/crates/parser/src/grammar/block.rs +++ b/crates/parser/src/grammar/block.rs @@ -1,5 +1,13 @@ use super::*; +/* +{ + / + / + .... + / +} +*/ pub fn block(p: &mut Parser) { p.inc_rcurly(); @@ -30,7 +38,7 @@ pub fn block(p: &mut Parser) { p.close(stmt_marker, StatementList); - p.expect(RCurly); + p.eat(RCurly); p.close(m, Block); From a10be252a1d9661aa5183883546fd5ccc6a531b4 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 17 Dec 2024 16:00:36 +0700 Subject: [PATCH 18/59] add scope parsing test --- crates/parser/Cargo.toml | 1 - crates/syntax/src/syntax.rs | 213 ++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 1 deletion(-) diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 5021d30..1ce7c59 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -12,6 +12,5 @@ rowan = "0.15.15" num-traits = "0.2" num-derive = "0.2" - [profile.dev] debug = 2 \ No newline at end of file diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 9b9202f..6cde0b1 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -289,3 +289,216 @@ mod tests { } } } + +#[cfg(test)] +mod grammar_tests { + use parser::{grammar::entry::Scope, input::Input, parser::Parser, token_kind::TokenKind}; + use rowan::ast::AstNode; + + use crate::{ + abstract_syntax_tree::{AstBlock, AstPragma, AstTemplateDef}, + syntax::SyntaxTreeBuilder, + syntax_node::SyntaxNode, + }; + + #[test] + fn pragma_happy_test() { + // parse source (string) into output tree + let version = r#"2.0.1"#; + let source = format!(r#"pragma circom {};"#, version); + let input = Input::new(&source); + let output = Parser::parsing_with_scope(&input, Scope::Pragma); + + // output is a tree whose node is index of token, no content of token + // convert output into green node + let mut builder = SyntaxTreeBuilder::new(&input); + builder.build(output); + let green = builder.finish(); + + // then cast green node into syntax node + let syntax = SyntaxNode::new_root(green); + + // cast syntax node into ast node to retrieve more information + let pragma = AstPragma::cast(syntax).expect("Can not cast syntax node into ast pragma"); + + // finally, assert with expect value + assert!(pragma.version().unwrap().syntax().kind() == TokenKind::Version); + assert!(pragma.version().unwrap().syntax().text() == version); + } + + #[test] + fn template_happy_test() { + // SOURCE & EXPECTED RESULT + const SOURCE: &str = r#"template MultiplierN (N, P, QQ) { + //Declaration of signals and components. + signal input in[N]; + signal output out; + component comp[N-1]; + + //Statements. + for(var i = 0; i < N-1; i++){ + comp[i] = Multiplier2(); + } + + // ... some more code (see below) + + }"#; + let expected_statements: Vec<&str> = vec![ + "signal input in[N];", + "signal output out;", + "component comp[N-1];", + "for(var i = 0; i < N-1; i++){ + comp[i] = Multiplier2(); + }", + ]; + let expected_name = "MultiplierN"; + let expected_first_param = "N"; + let expected_last_param = "QQ"; + + // parse source (string) into output tree + let input = Input::new(&SOURCE); + let output = Parser::parsing_with_scope(&input, Scope::Template); + + // output is a tree whose node is index of token, no content of token + // convert output into green node + let mut builder = SyntaxTreeBuilder::new(&input); + builder.build(output); + let green = builder.finish(); + + // then cast green node into syntax node + let syntax = SyntaxNode::new_root(green); + + // cast syntax node into ast node to retrieve more information + let template = + AstTemplateDef::cast(syntax).expect("Can not cast syntax node into ast template"); + + // finally, assert with expect value + + // name + let name = template + .name() + .expect("Can not extract template name") + .syntax() + .text(); + assert_eq!(expected_name, name); + + // parameter list + let first_param = template + .parameter_list() + .expect("Can not detect parameter list") + .syntax() + .first_child() + .unwrap() + .text(); + assert_eq!(expected_first_param, first_param); + let last_param = template + .parameter_list() + .expect("Can not detect parameter list") + .syntax() + .last_child() + .unwrap() + .text(); + assert_eq!(expected_last_param, last_param); + + // statements + let statements = template.statements().unwrap().statement_list(); + let statements: Vec = statements + .into_iter() + .map(|statement| statement.syntax().text().to_string()) + .collect(); + assert_eq!( + expected_statements.len(), + statements.len(), + "Number of statements is not match" + ); + + for id in 0..statements.len() { + assert_eq!(expected_statements[id].to_string(), statements[id]); + } + + // // input signal + // println!("find_input_signal: {:?}", template.find_input_signal()); + + // // output signal + // println!("find_output_signal: {:?}", template.find_output_signal()); + + // // internal signal + // println!("find_internal_signal: {:?}", template.find_internal_signal()); + + // // component + // println!("find_component: {:?}", template.find_component()); + } + + #[test] + fn block_happy_test() { + // SOURCE & EXPECTED RESULT + let source = r#"{ + //Declaration of signals. + signal input in[N]; + signal output out; + component comp[N-1]; + + //Statements. + for(var i = 0; i < N-1; i++){ + comp[i] = Multiplier2(); + } + comp[0].in1 <== in[0]; + comp[0].in2 <== in[1]; + for(var i = 0; i < N-2; i++){ + comp[i+1].in1 <== comp[i].out; + comp[i+1].in2 <== in[i+2]; + + } + out <== comp[N-2].out; +}"#; + let expected_statements = vec![ + "signal input in[N];", + "signal output out;", + "component comp[N-1];", + "for(var i = 0; i < N-1; i++){ + comp[i] = Multiplier2(); + }", + "comp[0].in1 <== in[0];", + "comp[0].in2 <== in[1];", + "for(var i = 0; i < N-2; i++){ + comp[i+1].in1 <== comp[i].out; + comp[i+1].in2 <== in[i+2]; + + }", + "out <== comp[N-2].out;", + ]; + + + // parse source (string) into output tree + let input = Input::new(&source); + let output = Parser::parsing_with_scope(&input, Scope::Block); + + // output is a tree whose node is index of token, no content of token + // convert output into green node + let mut builder = SyntaxTreeBuilder::new(&input); + builder.build(output); + let green = builder.finish(); + + // then cast green node into syntax node + let syntax = SyntaxNode::new_root(green); + + // cast syntax node into ast node to retrieve more information + let block = AstBlock::cast(syntax).expect("Can not cast syntax node into ast block"); + + // finally, assert with expect statements + let statements = block.statement_list().unwrap().statement_list(); + let statements: Vec = statements + .into_iter() + .map(|statement| statement.syntax().text().to_string()) + .collect(); + assert_eq!( + expected_statements.len(), + statements.len(), + "Number of statements is not match" + ); + + for id in 0..statements.len() { + assert_eq!(expected_statements[id].to_string(), statements[id]); + } + } +} From 47df964daedb4bca28ccead785dc348614fe9e88 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 17 Dec 2024 16:04:50 +0700 Subject: [PATCH 19/59] fix space in scope parsing test --- crates/syntax/src/syntax.rs | 49 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 6cde0b1..defc696 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -348,8 +348,8 @@ mod grammar_tests { "signal output out;", "component comp[N-1];", "for(var i = 0; i < N-1; i++){ - comp[i] = Multiplier2(); - }", + comp[i] = Multiplier2(); + }", ]; let expected_name = "MultiplierN"; let expected_first_param = "N"; @@ -433,42 +433,41 @@ mod grammar_tests { fn block_happy_test() { // SOURCE & EXPECTED RESULT let source = r#"{ - //Declaration of signals. - signal input in[N]; - signal output out; - component comp[N-1]; - - //Statements. - for(var i = 0; i < N-1; i++){ - comp[i] = Multiplier2(); - } - comp[0].in1 <== in[0]; - comp[0].in2 <== in[1]; - for(var i = 0; i < N-2; i++){ - comp[i+1].in1 <== comp[i].out; - comp[i+1].in2 <== in[i+2]; + //Declaration of signals. + signal input in[N]; + signal output out; + component comp[N-1]; - } - out <== comp[N-2].out; -}"#; + //Statements. + for(var i = 0; i < N-1; i++){ + comp[i] = Multiplier2(); + } + comp[0].in1 <== in[0]; + comp[0].in2 <== in[1]; + for(var i = 0; i < N-2; i++){ + comp[i+1].in1 <== comp[i].out; + comp[i+1].in2 <== in[i+2]; + + } + out <== comp[N-2].out; + }"#; let expected_statements = vec![ "signal input in[N];", "signal output out;", "component comp[N-1];", "for(var i = 0; i < N-1; i++){ - comp[i] = Multiplier2(); - }", + comp[i] = Multiplier2(); + }", "comp[0].in1 <== in[0];", "comp[0].in2 <== in[1];", "for(var i = 0; i < N-2; i++){ - comp[i+1].in1 <== comp[i].out; - comp[i+1].in2 <== in[i+2]; + comp[i+1].in1 <== comp[i].out; + comp[i+1].in2 <== in[i+2]; - }", + }", "out <== comp[N-2].out;", ]; - // parse source (string) into output tree let input = Input::new(&source); let output = Parser::parsing_with_scope(&input, Scope::Block); From 5c6cb56fe53f636b4ea1e82d4d0d1a52badb74af Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Thu, 19 Dec 2024 18:10:15 +0700 Subject: [PATCH 20/59] update snapshot test for syntax --- Cargo.toml | 1 + crates/parser/Cargo.toml | 1 + crates/parser/src/token_kind.rs | 3 +- crates/syntax/Cargo.toml | 10 +- ...ar_tests__block_happy_test_statements.snap | 12 + ...tests__template_happy_test_statements.snap | 8 + ...syntax__tests__syntax_test_1_children.snap | 17 ++ ...yntax__tests__syntax_test_2_functions.snap | 5 + ...yntax__tests__syntax_test_2_templates.snap | 5 + ...yntax__tests__syntax_test_5_templates.snap | 5 + ...yntax__tests__syntax_test_6_templates.snap | 5 + crates/syntax/src/syntax.rs | 252 +++++++----------- 12 files changed, 163 insertions(+), 161 deletions(-) create mode 100644 crates/syntax/src/snapshots/syntax__syntax__grammar_tests__block_happy_test_statements.snap create mode 100644 crates/syntax/src/snapshots/syntax__syntax__grammar_tests__template_happy_test_statements.snap create mode 100644 crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_1_children.snap create mode 100644 crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_functions.snap create mode 100644 crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_templates.snap create mode 100644 crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_5_templates.snap create mode 100644 crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_6_templates.snap diff --git a/Cargo.toml b/Cargo.toml index 5dc248b..bfbc8e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,6 @@ syntax = {path = './crates/syntax', version = "0.1.0"} circom-lsp = {path = './crates/lsp', version = "*"} common = { path = './crates/common', version = "*"} database = {path = "./crates/database", version = "*"} + [workspace.package] rust-version = "1.71" diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 1ce7c59..9070855 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -11,6 +11,7 @@ lsp-types = {version = "0.94.1", features = ["proposed"]} rowan = "0.15.15" num-traits = "0.2" num-derive = "0.2" +serde = "1.0.216" [profile.dev] debug = 2 \ No newline at end of file diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 9ebba15..9eba89c 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -1,6 +1,7 @@ use logos::Logos; +use serde::Serialize; -#[derive(Logos, Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord, Hash)] +#[derive(Logos, Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord, Hash, Serialize)] #[allow(non_camel_case_types)] #[repr(u16)] pub enum TokenKind { diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index d6a3b47..795f0b1 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -9,5 +9,13 @@ rust-version.workspace = true [dependencies] rowan = "0.15.13" parser.workspace = true - lsp-types = {version = "0.94.1", features = ["proposed"]} + +[dev-dependencies] +# for snapshot testing, yaml format +insta = { version = "1.41.1", features = ["yaml"] } + +[profile.dev.package] +# compile slightly slower once, but use less memory, have faster diffs +insta.opt-level = 3 +similar.opt-level = 3 \ No newline at end of file diff --git a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__block_happy_test_statements.snap b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__block_happy_test_statements.snap new file mode 100644 index 0000000..5db6859 --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__block_happy_test_statements.snap @@ -0,0 +1,12 @@ +--- +source: crates/syntax/src/syntax.rs +expression: statements +--- +- "signal input in[N];" +- "signal output out;" +- "component comp[N-1];" +- "for(var i = 0; i < N-1; i++){\n comp[i] = Multiplier2();\n }" +- "comp[0].in1 <== in[0];" +- "comp[0].in2 <== in[1];" +- "for(var i = 0; i < N-2; i++){\n comp[i+1].in1 <== comp[i].out;\n comp[i+1].in2 <== in[i+2];\n\n }" +- "out <== comp[N-2].out;" \ No newline at end of file diff --git a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__template_happy_test_statements.snap b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__template_happy_test_statements.snap new file mode 100644 index 0000000..74cf89f --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__template_happy_test_statements.snap @@ -0,0 +1,8 @@ +--- +source: crates/syntax/src/syntax.rs +expression: statements +--- +- "signal input in[N];" +- "signal output out;" +- "component comp[N-1];" +- "for(var i = 0; i < N-1; i++){\n comp[i] = Multiplier2();\n }" diff --git a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_1_children.snap b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_1_children.snap new file mode 100644 index 0000000..b1feddb --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_1_children.snap @@ -0,0 +1,17 @@ +--- +source: crates/syntax/src/syntax.rs +expression: children_string +--- +- pragma circom 2.0.0; +- "\n" +- "\n" +- " " +- "\n" +- " " +- "template Multiplier2 () {}" +- "\n" +- " " +- "template Multiplier2 () {}" +- " " +- "\n" +- " " diff --git a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_functions.snap b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_functions.snap new file mode 100644 index 0000000..49ea709 --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_functions.snap @@ -0,0 +1,5 @@ +--- +source: crates/syntax/src/syntax.rs +expression: function_names +--- +- "nbits" diff --git a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_templates.snap b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_templates.snap new file mode 100644 index 0000000..03a1b69 --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_templates.snap @@ -0,0 +1,5 @@ +--- +source: crates/syntax/src/syntax.rs +expression: template_names +--- +- "BinSum" diff --git a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_5_templates.snap b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_5_templates.snap new file mode 100644 index 0000000..53cde17 --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_5_templates.snap @@ -0,0 +1,5 @@ +--- +source: crates/syntax/src/syntax.rs +expression: template_names +--- +- "Multiplier2" diff --git a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_6_templates.snap b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_6_templates.snap new file mode 100644 index 0000000..53cde17 --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_6_templates.snap @@ -0,0 +1,5 @@ +--- +source: crates/syntax/src/syntax.rs +expression: template_names +--- +- "Multiplier2" diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index defc696..dcb98d0 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -58,118 +58,37 @@ impl<'a> SyntaxTreeBuilder<'a> { #[cfg(test)] mod tests { - use parser::token_kind::TokenKind::{self, *}; use std::hash::{DefaultHasher, Hash, Hasher}; - use rowan::{ast::AstNode, TextRange}; + use rowan::ast::AstNode; use crate::{abstract_syntax_tree::AstCircomProgram, test_programs}; use super::SyntaxTreeBuilder; - fn generate_expected_token_kind(ast: &AstCircomProgram) { - let children = ast - .syntax() - .first_child() - .unwrap() - .siblings(rowan::Direction::Next); - - println!("vec!["); - for child in children { - println!("{:?},", child.kind()); - } - println!("];"); - } - - fn generate_expected_token_range(ast: &AstCircomProgram) { - let children = ast - .syntax() - .first_child() - .unwrap() - .siblings(rowan::Direction::Next); - - println!("vec!["); - for child in children { - println!( - "TextRange::new({:?}.into(), {:?}.into()), ", - child.text_range().start(), - child.text_range().end() - ); - } - println!("];"); - } - - fn check_ast_children( - ast: &AstCircomProgram, - expected_kinds: &Vec, - expected_ranges: &Vec, - ) { - let children = ast - .syntax() - .first_child() - .unwrap() - .siblings(rowan::Direction::Next); - - let mut kind_iterator = expected_kinds.iter(); - let mut range_iterator = expected_ranges.iter(); - - for child in children { - if let (Some(expected_kind), Some(expected_range)) = - (kind_iterator.next(), range_iterator.next()) - { - assert_eq!(child.kind(), *expected_kind); - assert_eq!(child.text_range(), *expected_range); - } else { - panic!("Mismatched number of children and expected values"); - } - } - println!(); - } - #[test] fn syntax_test_1() { let source: &str = test_programs::PARSER_TEST_1; - let expected_pragma = "pragma circom 2.0.0;".to_string(); - let expected_kinds = vec![ - Pragma, - EndLine, - EndLine, - WhiteSpace, - EndLine, - WhiteSpace, - TemplateDef, - EndLine, - WhiteSpace, - TemplateDef, - WhiteSpace, - EndLine, - WhiteSpace, - ]; - let expected_ranges = vec![ - TextRange::new(0.into(), 20.into()), - TextRange::new(20.into(), 21.into()), - TextRange::new(21.into(), 22.into()), - TextRange::new(22.into(), 26.into()), - TextRange::new(26.into(), 27.into()), - TextRange::new(27.into(), 31.into()), - TextRange::new(31.into(), 57.into()), - TextRange::new(57.into(), 58.into()), - TextRange::new(58.into(), 62.into()), - TextRange::new(62.into(), 88.into()), - TextRange::new(88.into(), 89.into()), - TextRange::new(89.into(), 90.into()), - TextRange::new(90.into(), 94.into()), - ]; - let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - check_ast_children(&ast, &expected_kinds, &expected_ranges); + // check_ast_children + let children = ast + .syntax() + .first_child() + .unwrap() + .siblings(rowan::Direction::Next); + let mut children_string = Vec::new(); + + for child in children.into_iter() { + children_string.push(child.text().to_string()); + } + insta::assert_yaml_snapshot!("syntax_test_1_children", children_string); // check pragma let pragma = ast.pragma().unwrap().syntax().text().to_string(); - assert_eq!(pragma, expected_pragma, "Pragma is not correct!"); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); // check ast hash let mut hasher = DefaultHasher::default(); @@ -212,24 +131,29 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - println!("Pragma: {:?}", ast.pragma().unwrap().syntax().text()); + let pragma = ast.pragma().unwrap().syntax().text().to_string(); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - print!("Templates: "); let templates = ast.template_list(); + let mut template_names = Vec::new(); for template in templates.iter() { - print!("{:?} ", template.name().unwrap().syntax().text()); // leading whitespaces - // print!("{:?} ", template.syntax().text()); // leading whitespaces + let template_name = template.name().unwrap().syntax().text().to_string(); + template_names.push(template_name); } - println!(); + insta::assert_yaml_snapshot!("syntax_test_2_templates", template_names); - print!("Functions: "); let functions = ast.function_list(); + let mut function_names = Vec::new(); for function in functions.iter() { - print!("{:?} ", function.function_name().unwrap().syntax().text()); - // leading whitespaces - // print!("{:?} ", function.syntax().text()); // leading whitespaces + let function_name = function + .function_name() + .unwrap() + .syntax() + .text() + .to_string(); + function_names.push(function_name); } - println!(); + insta::assert_yaml_snapshot!("syntax_test_2_functions", function_names); } } @@ -240,11 +164,18 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - println!("Pragma: {:?}", ast.pragma().unwrap().syntax().text()); - println!( - "Pragma version: {:?}", - ast.pragma().unwrap().version().unwrap().syntax().text() - ); + let pragma = ast.pragma().unwrap().syntax().text().to_string(); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); + + let pragma_version = ast + .pragma() + .unwrap() + .version() + .unwrap() + .syntax() + .text() + .to_string(); + insta::assert_yaml_snapshot!(pragma_version, @"2.0.0"); } } @@ -255,11 +186,18 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - println!("Pragma: {:?}", ast.pragma().unwrap().syntax().text()); - println!( - "Pragma version: {:?}", - ast.pragma().unwrap().version().unwrap().syntax().text() - ); + let pragma = ast.pragma().unwrap().syntax().text().to_string(); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); + + let pragma_version = ast + .pragma() + .unwrap() + .version() + .unwrap() + .syntax() + .text() + .to_string(); + insta::assert_yaml_snapshot!(pragma_version, @"2.0.0"); } } @@ -270,9 +208,16 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - println!("pragma: {:?}", ast.pragma()); - println!("template list: {:?}", ast.template_list()); - // assert!(ast.pragma().is_none(), "No pragma in source code"); + let pragma = ast.pragma().is_none(); + insta::assert_yaml_snapshot!(pragma, @"true"); + + let templates = ast.template_list(); + let mut template_names = Vec::new(); + for template in templates.iter() { + let template_name = template.name().unwrap().syntax().text().to_string(); + template_names.push(template_name); + } + insta::assert_yaml_snapshot!("syntax_test_5_templates", template_names); } } @@ -283,16 +228,23 @@ mod tests { let syntax = SyntaxTreeBuilder::syntax_tree(source); if let Some(ast) = AstCircomProgram::cast(syntax) { - println!("{:?}", ast.pragma()); - println!("template list: {:?}", ast.template_list()); - // assert!(ast.pragma().is_none(), "No pragma in source code"); + let pragma = ast.pragma().is_none(); + insta::assert_yaml_snapshot!(pragma, @"true"); + + let templates = ast.template_list(); + let mut template_names = Vec::new(); + for template in templates.iter() { + let template_name = template.name().unwrap().syntax().text().to_string(); + template_names.push(template_name); + } + insta::assert_yaml_snapshot!("syntax_test_6_templates", template_names); } } } #[cfg(test)] mod grammar_tests { - use parser::{grammar::entry::Scope, input::Input, parser::Parser, token_kind::TokenKind}; + use parser::{grammar::entry::Scope, input::Input, parser::Parser}; use rowan::ast::AstNode; use crate::{ @@ -322,8 +274,11 @@ mod grammar_tests { let pragma = AstPragma::cast(syntax).expect("Can not cast syntax node into ast pragma"); // finally, assert with expect value - assert!(pragma.version().unwrap().syntax().kind() == TokenKind::Version); - assert!(pragma.version().unwrap().syntax().text() == version); + let pragma_versison_kind = pragma.version().unwrap().syntax().kind(); + insta::assert_yaml_snapshot!(pragma_versison_kind, @"Version"); + + let pragma_versison_text = pragma.version().unwrap().syntax().text().to_string(); + insta::assert_yaml_snapshot!(pragma_versison_text, @"2.0.1"); } #[test] @@ -343,17 +298,6 @@ mod grammar_tests { // ... some more code (see below) }"#; - let expected_statements: Vec<&str> = vec![ - "signal input in[N];", - "signal output out;", - "component comp[N-1];", - "for(var i = 0; i < N-1; i++){ - comp[i] = Multiplier2(); - }", - ]; - let expected_name = "MultiplierN"; - let expected_first_param = "N"; - let expected_last_param = "QQ"; // parse source (string) into output tree let input = Input::new(&SOURCE); @@ -379,8 +323,9 @@ mod grammar_tests { .name() .expect("Can not extract template name") .syntax() - .text(); - assert_eq!(expected_name, name); + .text() + .to_string(); + insta::assert_yaml_snapshot!(name, @"MultiplierN"); // parameter list let first_param = template @@ -389,16 +334,19 @@ mod grammar_tests { .syntax() .first_child() .unwrap() - .text(); - assert_eq!(expected_first_param, first_param); + .text() + .to_string(); + insta::assert_yaml_snapshot!(first_param, @"N"); + let last_param = template .parameter_list() .expect("Can not detect parameter list") .syntax() .last_child() .unwrap() - .text(); - assert_eq!(expected_last_param, last_param); + .text() + .to_string(); + insta::assert_yaml_snapshot!(last_param, @"QQ"); // statements let statements = template.statements().unwrap().statement_list(); @@ -406,15 +354,7 @@ mod grammar_tests { .into_iter() .map(|statement| statement.syntax().text().to_string()) .collect(); - assert_eq!( - expected_statements.len(), - statements.len(), - "Number of statements is not match" - ); - - for id in 0..statements.len() { - assert_eq!(expected_statements[id].to_string(), statements[id]); - } + insta::assert_yaml_snapshot!("template_happy_test_statements", statements); // // input signal // println!("find_input_signal: {:?}", template.find_input_signal()); @@ -451,6 +391,7 @@ mod grammar_tests { } out <== comp[N-2].out; }"#; + /* let expected_statements = vec![ "signal input in[N];", "signal output out;", @@ -467,6 +408,7 @@ mod grammar_tests { }", "out <== comp[N-2].out;", ]; + */ // parse source (string) into output tree let input = Input::new(&source); @@ -490,14 +432,6 @@ mod grammar_tests { .into_iter() .map(|statement| statement.syntax().text().to_string()) .collect(); - assert_eq!( - expected_statements.len(), - statements.len(), - "Number of statements is not match" - ); - - for id in 0..statements.len() { - assert_eq!(expected_statements[id].to_string(), statements[id]); - } + insta::assert_yaml_snapshot!("block_happy_test_statements", statements); } } From 372efd3d6a6510b100305b9d8c9d751f2d21c723 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Thu, 19 Dec 2024 18:39:51 +0700 Subject: [PATCH 21/59] refactor syntax test --- .gitignore | 4 +- crates/syntax/src/syntax.rs | 331 +++++++++++++++--------------------- 2 files changed, 144 insertions(+), 191 deletions(-) diff --git a/.gitignore b/.gitignore index 6f429f5..165e8e1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ node_modules .vscode-test /target Cargo.lock -assets \ No newline at end of file +assets +*.new +*.pending-snap \ No newline at end of file diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index dcb98d0..0c1d1b8 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -66,198 +66,178 @@ mod tests { use super::SyntaxTreeBuilder; - #[test] - fn syntax_test_1() { - let source: &str = test_programs::PARSER_TEST_1; - + fn ast_from_source(source: &str) -> AstCircomProgram { let syntax = SyntaxTreeBuilder::syntax_tree(source); + AstCircomProgram::cast(syntax).unwrap() + } - if let Some(ast) = AstCircomProgram::cast(syntax) { - // check_ast_children - let children = ast - .syntax() - .first_child() - .unwrap() - .siblings(rowan::Direction::Next); - let mut children_string = Vec::new(); - - for child in children.into_iter() { - children_string.push(child.text().to_string()); - } - insta::assert_yaml_snapshot!("syntax_test_1_children", children_string); - - // check pragma - let pragma = ast.pragma().unwrap().syntax().text().to_string(); - insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - - // check ast hash - let mut hasher = DefaultHasher::default(); - ast.syntax().hash(&mut hasher); - let _ast_hash = hasher.finish(); - - // check template hash - let mut h1 = DefaultHasher::default(); - let mut h2 = DefaultHasher::default(); - - let template = ast.template_list(); - - template[0].syntax().hash(&mut h1); - template[1].syntax().hash(&mut h2); - - assert_ne!( - h1.finish(), - h2.finish(), - "Templates with same syntax should have different hashes!" - ); - - // check template syntax (text & green node) - assert_eq!( - template[0].syntax().text(), - template[1].syntax().text(), - "The syntax (as text) of template 1 and 2 must be the same!" - ); - assert_eq!( - template[0].syntax().green(), - template[1].syntax().green(), - "The syntax (as green node) of template 1 and 2 must be the same!!" - ); - } + fn children_from_ast(ast: &AstCircomProgram) -> Vec { + let children = ast + .syntax() + .first_child() + .unwrap() + .siblings(rowan::Direction::Next) + .into_iter() + .map(|child| child.text().to_string()) + .collect(); + + children } - #[test] - fn syntax_test_2() { - let source = test_programs::PARSER_TEST_2; + fn pragma_string_from_ast(ast: &AstCircomProgram) -> String { + ast.pragma().unwrap().syntax().text().to_string() + } - let syntax = SyntaxTreeBuilder::syntax_tree(source); + fn pragma_version_from_ast(ast: &AstCircomProgram) -> String { + ast.pragma() + .unwrap() + .version() + .unwrap() + .syntax() + .text() + .to_string() + } - if let Some(ast) = AstCircomProgram::cast(syntax) { - let pragma = ast.pragma().unwrap().syntax().text().to_string(); - insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); + fn template_names_from_ast(ast: &AstCircomProgram) -> Vec { + let templates = ast + .template_list() + .iter() + .map(|template| template.name().unwrap().syntax().text().to_string()) + .collect(); - let templates = ast.template_list(); - let mut template_names = Vec::new(); - for template in templates.iter() { - let template_name = template.name().unwrap().syntax().text().to_string(); - template_names.push(template_name); - } - insta::assert_yaml_snapshot!("syntax_test_2_templates", template_names); + templates + } - let functions = ast.function_list(); - let mut function_names = Vec::new(); - for function in functions.iter() { - let function_name = function + fn function_names_from_ast(ast: &AstCircomProgram) -> Vec { + let functions = ast + .function_list() + .iter() + .map(|function| { + function .function_name() .unwrap() .syntax() .text() - .to_string(); - function_names.push(function_name); - } - insta::assert_yaml_snapshot!("syntax_test_2_functions", function_names); - } + .to_string() + }) + .collect(); + + functions } #[test] - fn syntax_test_3() { - let source = test_programs::PARSER_TEST_3; - - let syntax = SyntaxTreeBuilder::syntax_tree(source); - - if let Some(ast) = AstCircomProgram::cast(syntax) { - let pragma = ast.pragma().unwrap().syntax().text().to_string(); - insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - - let pragma_version = ast - .pragma() - .unwrap() - .version() - .unwrap() - .syntax() - .text() - .to_string(); - insta::assert_yaml_snapshot!(pragma_version, @"2.0.0"); - } + fn syntax_test_1() { + let ast = ast_from_source(test_programs::PARSER_TEST_1); + + // check_ast_children + let children = children_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_1_children", children); + + // check pragma + let pragma = pragma_string_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); + + // check ast hash + let mut hasher = DefaultHasher::default(); + ast.syntax().hash(&mut hasher); + let _ast_hash = hasher.finish(); + + // check template hash + let mut h1 = DefaultHasher::default(); + let mut h2 = DefaultHasher::default(); + + let template = ast.template_list(); + + template[0].syntax().hash(&mut h1); + template[1].syntax().hash(&mut h2); + + assert_ne!( + h1.finish(), + h2.finish(), + "Templates with same syntax should have different hashes!" + ); + + // check template syntax (text & green node) + assert_eq!( + template[0].syntax().text(), + template[1].syntax().text(), + "The syntax (as text) of template 1 and 2 must be the same!" + ); + assert_eq!( + template[0].syntax().green(), + template[1].syntax().green(), + "The syntax (as green node) of template 1 and 2 must be the same!!" + ); } #[test] - fn syntax_test_4() { - let source = test_programs::PARSER_TEST_4; + fn syntax_test_2() { + let ast = ast_from_source(test_programs::PARSER_TEST_2); - let syntax = SyntaxTreeBuilder::syntax_tree(source); + let pragma = pragma_string_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - if let Some(ast) = AstCircomProgram::cast(syntax) { - let pragma = ast.pragma().unwrap().syntax().text().to_string(); - insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - - let pragma_version = ast - .pragma() - .unwrap() - .version() - .unwrap() - .syntax() - .text() - .to_string(); - insta::assert_yaml_snapshot!(pragma_version, @"2.0.0"); - } + let template_names = template_names_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_2_templates", template_names); + + let function_names = function_names_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_2_functions", function_names); } #[test] - fn syntax_test_5() { - let source = test_programs::PARSER_TEST_5; + fn syntax_test_3() { + let ast = ast_from_source(test_programs::PARSER_TEST_3); + let pragma = pragma_string_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - let syntax = SyntaxTreeBuilder::syntax_tree(source); + let pragma_version = pragma_version_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma_version, @"2.0.0"); + } - if let Some(ast) = AstCircomProgram::cast(syntax) { - let pragma = ast.pragma().is_none(); - insta::assert_yaml_snapshot!(pragma, @"true"); + #[test] + fn syntax_test_4() { + let ast = ast_from_source(test_programs::PARSER_TEST_4); + let pragma = pragma_string_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - let templates = ast.template_list(); - let mut template_names = Vec::new(); - for template in templates.iter() { - let template_name = template.name().unwrap().syntax().text().to_string(); - template_names.push(template_name); - } - insta::assert_yaml_snapshot!("syntax_test_5_templates", template_names); - } + let pragma_version = pragma_version_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma_version, @"2.0.0"); } #[test] - fn syntax_test_6() { - let source = test_programs::PARSER_TEST_6; + fn syntax_test_5() { + let ast = ast_from_source(test_programs::PARSER_TEST_5); + let pragma = ast.pragma().is_none(); + insta::assert_yaml_snapshot!(pragma, @"true"); - let syntax = SyntaxTreeBuilder::syntax_tree(source); + let template_names = template_names_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_5_templates", template_names); + } - if let Some(ast) = AstCircomProgram::cast(syntax) { - let pragma = ast.pragma().is_none(); - insta::assert_yaml_snapshot!(pragma, @"true"); + #[test] + fn syntax_test_6() { + let ast = ast_from_source(test_programs::PARSER_TEST_6); + let pragma = ast.pragma().is_none(); + insta::assert_yaml_snapshot!(pragma, @"true"); - let templates = ast.template_list(); - let mut template_names = Vec::new(); - for template in templates.iter() { - let template_name = template.name().unwrap().syntax().text().to_string(); - template_names.push(template_name); - } - insta::assert_yaml_snapshot!("syntax_test_6_templates", template_names); - } + let template_names = template_names_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_6_templates", template_names); } } #[cfg(test)] mod grammar_tests { + use parser::{grammar::entry::Scope, input::Input, parser::Parser}; - use rowan::ast::AstNode; + use rowan::{ast::AstNode, SyntaxNode}; use crate::{ abstract_syntax_tree::{AstBlock, AstPragma, AstTemplateDef}, syntax::SyntaxTreeBuilder, - syntax_node::SyntaxNode, + syntax_node::CircomLanguage, }; - #[test] - fn pragma_happy_test() { - // parse source (string) into output tree - let version = r#"2.0.1"#; - let source = format!(r#"pragma circom {};"#, version); + fn syntax_node_from_source(source: &str) -> SyntaxNode { let input = Input::new(&source); let output = Parser::parsing_with_scope(&input, Scope::Pragma); @@ -270,6 +250,17 @@ mod grammar_tests { // then cast green node into syntax node let syntax = SyntaxNode::new_root(green); + syntax + } + + #[test] + fn pragma_happy_test() { + // parse source (string) into output tree + let version = r#"2.0.1"#; + let source = format!(r#"pragma circom {};"#, version); + + let syntax = syntax_node_from_source(&source); + // cast syntax node into ast node to retrieve more information let pragma = AstPragma::cast(syntax).expect("Can not cast syntax node into ast pragma"); @@ -299,18 +290,7 @@ mod grammar_tests { }"#; - // parse source (string) into output tree - let input = Input::new(&SOURCE); - let output = Parser::parsing_with_scope(&input, Scope::Template); - - // output is a tree whose node is index of token, no content of token - // convert output into green node - let mut builder = SyntaxTreeBuilder::new(&input); - builder.build(output); - let green = builder.finish(); - - // then cast green node into syntax node - let syntax = SyntaxNode::new_root(green); + let syntax = syntax_node_from_source(&SOURCE); // cast syntax node into ast node to retrieve more information let template = @@ -391,37 +371,8 @@ mod grammar_tests { } out <== comp[N-2].out; }"#; - /* - let expected_statements = vec![ - "signal input in[N];", - "signal output out;", - "component comp[N-1];", - "for(var i = 0; i < N-1; i++){ - comp[i] = Multiplier2(); - }", - "comp[0].in1 <== in[0];", - "comp[0].in2 <== in[1];", - "for(var i = 0; i < N-2; i++){ - comp[i+1].in1 <== comp[i].out; - comp[i+1].in2 <== in[i+2]; - }", - "out <== comp[N-2].out;", - ]; - */ - - // parse source (string) into output tree - let input = Input::new(&source); - let output = Parser::parsing_with_scope(&input, Scope::Block); - - // output is a tree whose node is index of token, no content of token - // convert output into green node - let mut builder = SyntaxTreeBuilder::new(&input); - builder.build(output); - let green = builder.finish(); - - // then cast green node into syntax node - let syntax = SyntaxNode::new_root(green); + let syntax = syntax_node_from_source(&source); // cast syntax node into ast node to retrieve more information let block = AstBlock::cast(syntax).expect("Can not cast syntax node into ast block"); From 46929c2d65db1c28ddf66117c815285af4ca8fca Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Fri, 20 Dec 2024 12:34:32 +0700 Subject: [PATCH 22/59] update input tests with snapshot --- crates/parser/Cargo.toml | 11 +- crates/parser/src/input.rs | 265 +----------------- ...ser__input__tests__test_comment_block.snap | 43 +++ ...ser__input__tests__test_comment_error.snap | 34 +++ .../parser__input__tests__test_function.snap | 217 ++++++++++++++ .../parser__input__tests__test_pragma.snap | 52 ++++ 6 files changed, 364 insertions(+), 258 deletions(-) create mode 100644 crates/parser/src/snapshots/parser__input__tests__test_comment_block.snap create mode 100644 crates/parser/src/snapshots/parser__input__tests__test_comment_error.snap create mode 100644 crates/parser/src/snapshots/parser__input__tests__test_function.snap create mode 100644 crates/parser/src/snapshots/parser__input__tests__test_pragma.snap diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 9070855..0173d54 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -14,4 +14,13 @@ num-derive = "0.2" serde = "1.0.216" [profile.dev] -debug = 2 \ No newline at end of file +debug = 2 + +[dev-dependencies] +# for snapshot testing, yaml format +insta = { version = "1.41.1", features = ["yaml"] } + +[profile.dev.package] +# compile slightly slower once, but use less memory, have faster diffs +insta.opt-level = 3 +similar.opt-level = 3 \ No newline at end of file diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index 8ddf602..a37579e 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -1,10 +1,11 @@ use std::ops::Range; use logos::Lexer; +use serde::Serialize; use crate::token_kind::TokenKind; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Serialize)] pub struct Input<'a> { kind: Vec, source: &'a str, @@ -81,65 +82,12 @@ impl<'a> Input<'a> { #[cfg(test)] mod tests { - use crate::token_kind::TokenKind::{self, *}; - use super::Input; - fn test(source: &str, expected_input: Input) { + fn test(source: &str, snapshot_name: &str) { let input = Input::new(&source); - assert_eq!( - expected_input, input, - "Tokens extract from source code are not correct" - ); - - // test size method - let expected_size = input.kind.len(); - let size = input.size(); - assert_eq!(expected_size, size, "size method failed"); - - // test methods with index out of bound - let index = input.kind.len(); - - let expected_token_value = None; - let token_value = input.token_value(index); - assert_eq!( - expected_token_value, token_value, - "token_value failed (case: index out of bound)" - ); - - let expected_kind = TokenKind::EOF; - let kind = input.kind_of(index); - assert_eq!( - expected_kind, kind, - "kind_of failed (case: index out of bound)" - ); - - let expected_position = None; - let position = input.position_of(index); - assert_eq!( - expected_position, position, - "position_of failed (case: index out of bound)" - ); - - // test methods with index in bound - if input.size() == 0 { - return; - } - - let index = input.size() / 2; // a valid index if input size > 0 - - let expected_token_value = &input.source[input.position[index].clone()]; - let token_value = input.token_value(index).unwrap(); - assert_eq!(expected_token_value, token_value, "token_value failed"); - - let expected_kind = input.kind[index]; - let kind = input.kind_of(index); - assert_eq!(expected_kind, kind, "kind_of failed"); - - let expected_position = input.position[index].clone(); - let position = input.position_of(index).unwrap(); - assert_eq!(expected_position, position, "position_of failed"); + insta::assert_yaml_snapshot!(snapshot_name, input); } #[test] @@ -148,40 +96,7 @@ mod tests { /*a + b == 10*/ a + 10 "#; - - let expected_input = Input { - kind: vec![ - TokenKind::EndLine, - TokenKind::WhiteSpace, - TokenKind::BlockComment, - TokenKind::EndLine, - TokenKind::WhiteSpace, - TokenKind::Identifier, - TokenKind::WhiteSpace, - TokenKind::Add, - TokenKind::WhiteSpace, - TokenKind::Number, - TokenKind::EndLine, - TokenKind::WhiteSpace, - ], - source: &source, - position: vec![ - { 0..1 }, - { 1..9 }, - { 9..24 }, - { 24..25 }, - { 25..33 }, - { 33..34 }, - { 34..35 }, - { 35..36 }, - { 36..37 }, - { 37..39 }, - { 39..40 }, - { 40..44 }, - ], - }; - - test(source, expected_input); + test(source, "test_comment_block"); } #[test] @@ -194,34 +109,7 @@ mod tests { /* "#; - - let expected_input = Input { - kind: vec![ - TokenKind::EndLine, - TokenKind::WhiteSpace, - TokenKind::Pragma, - TokenKind::WhiteSpace, - TokenKind::Version, - TokenKind::Semicolon, - TokenKind::EndLine, - TokenKind::WhiteSpace, - TokenKind::Error, - ], - source: &source, - position: vec![ - 0..1, - 1..9, - 9..15, - 15..16, - 16..21, - 21..22, - 22..23, - 23..31, - 31..94, - ], - }; - - test(source, expected_input); + test(source, "test_comment_error"); } #[test] @@ -232,46 +120,7 @@ mod tests { pragma circom 2.0.0; "#; - - let expected_input = Input { - kind: vec![ - EndLine, - WhiteSpace, - BlockComment, - EndLine, - EndLine, - WhiteSpace, - Pragma, - WhiteSpace, - Circom, - WhiteSpace, - Version, - Semicolon, - EndLine, - EndLine, - WhiteSpace, - ], - source: &source, - position: vec![ - 0..1, - 1..9, - 9..38, - 38..39, - 39..40, - 40..44, - 44..50, - 50..51, - 51..57, - 57..58, - 58..63, - 63..64, - 64..65, - 65..66, - 66..70, - ], - }; - - test(source, expected_input); + test(source, "test_pragma"); } #[test] @@ -286,104 +135,6 @@ mod tests { } return r; }"#; - - let expected_input = Input { - kind: vec![ - EndLine, WhiteSpace, FunctionKw, WhiteSpace, Identifier, LParen, Identifier, - RParen, WhiteSpace, LCurly, EndLine, WhiteSpace, VarKw, WhiteSpace, Identifier, - WhiteSpace, Assign, WhiteSpace, Number, Semicolon, EndLine, WhiteSpace, VarKw, - WhiteSpace, Identifier, WhiteSpace, Assign, WhiteSpace, Number, Semicolon, EndLine, - WhiteSpace, WhileKw, WhiteSpace, LParen, Identifier, Sub, Number, LessThan, - Identifier, RParen, WhiteSpace, LCurly, EndLine, WhiteSpace, Identifier, Add, Add, - Semicolon, EndLine, WhiteSpace, Identifier, WhiteSpace, Mul, Assign, WhiteSpace, - Number, Semicolon, EndLine, WhiteSpace, RCurly, EndLine, WhiteSpace, ReturnKw, - WhiteSpace, Identifier, Semicolon, EndLine, WhiteSpace, RCurly, - ], - source: &source, - position: vec![ - 0..1, - 1..5, - 5..13, - 13..14, - 14..19, - 19..20, - 20..21, - 21..22, - 22..23, - 23..24, - 24..25, - 25..33, - 33..36, - 36..37, - 37..38, - 38..39, - 39..40, - 40..41, - 41..42, - 42..43, - 43..44, - 44..52, - 52..55, - 55..56, - 56..57, - 57..58, - 58..59, - 59..60, - 60..61, - 61..62, - 62..63, - 63..71, - 71..76, - 76..77, - 77..78, - 78..79, - 79..80, - 80..81, - 81..82, - 82..83, - 83..84, - 84..85, - 85..86, - 86..87, - 87..99, - 99..100, - 100..101, - 101..102, - 102..103, - 103..104, - 104..116, - 116..117, - 117..118, - 118..119, - 119..120, - 120..121, - 121..122, - 122..123, - 123..124, - 124..132, - 132..133, - 133..134, - 134..142, - 142..148, - 148..149, - 149..150, - 150..151, - 151..152, - 152..156, - 156..157, - ], - }; - - test(source, expected_input); + test(source, "test_function"); } - - // #[test] - // fn test_gen() { - // let source = r#" - // "#; - - // let input = Input::new(&source); - // println!("{:?}", input.kind); - // println!("{:?}", input.position); - // } } diff --git a/crates/parser/src/snapshots/parser__input__tests__test_comment_block.snap b/crates/parser/src/snapshots/parser__input__tests__test_comment_block.snap new file mode 100644 index 0000000..f6bdb27 --- /dev/null +++ b/crates/parser/src/snapshots/parser__input__tests__test_comment_block.snap @@ -0,0 +1,43 @@ +--- +source: crates/parser/src/input.rs +expression: input +--- +kind: + - EndLine + - WhiteSpace + - BlockComment + - EndLine + - WhiteSpace + - Identifier + - WhiteSpace + - Add + - WhiteSpace + - Number + - EndLine + - WhiteSpace +source: "\n /*a + b == 10*/\n a + 10\n " +position: + - start: 0 + end: 1 + - start: 1 + end: 9 + - start: 9 + end: 24 + - start: 24 + end: 25 + - start: 25 + end: 33 + - start: 33 + end: 34 + - start: 34 + end: 35 + - start: 35 + end: 36 + - start: 36 + end: 37 + - start: 37 + end: 39 + - start: 39 + end: 40 + - start: 40 + end: 44 diff --git a/crates/parser/src/snapshots/parser__input__tests__test_comment_error.snap b/crates/parser/src/snapshots/parser__input__tests__test_comment_error.snap new file mode 100644 index 0000000..f8307a5 --- /dev/null +++ b/crates/parser/src/snapshots/parser__input__tests__test_comment_error.snap @@ -0,0 +1,34 @@ +--- +source: crates/parser/src/input.rs +expression: input +--- +kind: + - EndLine + - WhiteSpace + - Pragma + - WhiteSpace + - Version + - Semicolon + - EndLine + - WhiteSpace + - Error +source: "\n pragma 2.1.1;\n /*a + b == 10*\n a + 10\n template\n\n /*\n " +position: + - start: 0 + end: 1 + - start: 1 + end: 9 + - start: 9 + end: 15 + - start: 15 + end: 16 + - start: 16 + end: 21 + - start: 21 + end: 22 + - start: 22 + end: 23 + - start: 23 + end: 31 + - start: 31 + end: 94 diff --git a/crates/parser/src/snapshots/parser__input__tests__test_function.snap b/crates/parser/src/snapshots/parser__input__tests__test_function.snap new file mode 100644 index 0000000..dd235e2 --- /dev/null +++ b/crates/parser/src/snapshots/parser__input__tests__test_function.snap @@ -0,0 +1,217 @@ +--- +source: crates/parser/src/input.rs +expression: input +--- +kind: + - EndLine + - WhiteSpace + - FunctionKw + - WhiteSpace + - Identifier + - LParen + - Identifier + - RParen + - WhiteSpace + - LCurly + - EndLine + - WhiteSpace + - VarKw + - WhiteSpace + - Identifier + - WhiteSpace + - Assign + - WhiteSpace + - Number + - Semicolon + - EndLine + - WhiteSpace + - VarKw + - WhiteSpace + - Identifier + - WhiteSpace + - Assign + - WhiteSpace + - Number + - Semicolon + - EndLine + - WhiteSpace + - WhileKw + - WhiteSpace + - LParen + - Identifier + - Sub + - Number + - LessThan + - Identifier + - RParen + - WhiteSpace + - LCurly + - EndLine + - WhiteSpace + - Identifier + - Add + - Add + - Semicolon + - EndLine + - WhiteSpace + - Identifier + - WhiteSpace + - Mul + - Assign + - WhiteSpace + - Number + - Semicolon + - EndLine + - WhiteSpace + - RCurly + - EndLine + - WhiteSpace + - ReturnKw + - WhiteSpace + - Identifier + - Semicolon + - EndLine + - WhiteSpace + - RCurly +source: "\n function nbits(a) {\n var n = 1;\n var r = 0;\n while (n-1 Date: Wed, 25 Dec 2024 12:17:10 +0700 Subject: [PATCH 23/59] change param type in find signal into str --- crates/parser/src/parser.rs | 4 ++-- .../src/abstract_syntax_tree/template.rs | 13 ++++++------- crates/syntax/src/syntax.rs | 19 +++++++++++-------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index a4f0efe..2fbe667 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -181,8 +181,8 @@ impl<'a> Parser<'a> { if self.at(kind) { self.advance(); } else { - // error report - // println!("expect {:?} but got {:?}", kind, current); + // TODO + // advance_with_error: ("expect {:?} but got {:?}", kind, current); } } diff --git a/crates/syntax/src/abstract_syntax_tree/template.rs b/crates/syntax/src/abstract_syntax_tree/template.rs index ab2f354..7253b12 100644 --- a/crates/syntax/src/abstract_syntax_tree/template.rs +++ b/crates/syntax/src/abstract_syntax_tree/template.rs @@ -1,5 +1,4 @@ use parser::token_kind::TokenKind::*; -use rowan::SyntaxText; use crate::syntax_node::CircomLanguage; use crate::syntax_node::SyntaxNode; @@ -45,11 +44,11 @@ impl AstTemplateDef { None } - pub fn find_input_signal(&self, name: &SyntaxText) -> Option { + pub fn find_input_signal(&self, name: &str) -> Option { if let Some(statements) = self.statements() { for input_signal in statements.find_children::() { if let Some(signal_name) = input_signal.name() { - if signal_name.equal(name) { + if signal_name.syntax().text() == name { return Some(input_signal); } } @@ -58,11 +57,11 @@ impl AstTemplateDef { None } - pub fn find_output_signal(&self, name: &SyntaxText) -> Option { + pub fn find_output_signal(&self, name: &str) -> Option { if let Some(statements) = self.statements() { for input_signal in statements.find_children::() { if let Some(signal_name) = input_signal.name() { - if signal_name.equal(name) { + if signal_name.syntax().text() == name { return Some(input_signal); } } @@ -71,11 +70,11 @@ impl AstTemplateDef { None } - pub fn find_internal_signal(&self, name: &SyntaxText) -> Option { + pub fn find_internal_signal(&self, name: &str) -> Option { if let Some(statements) = self.statements() { for signal in statements.find_children::() { if let Some(signal_name) = signal.name() { - if signal_name.equal(name) { + if signal_name.syntax().text() == name { return Some(signal); } } diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 0c1d1b8..a2fe669 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -230,16 +230,15 @@ mod grammar_tests { use parser::{grammar::entry::Scope, input::Input, parser::Parser}; use rowan::{ast::AstNode, SyntaxNode}; - use crate::{ - abstract_syntax_tree::{AstBlock, AstPragma, AstTemplateDef}, + abstract_syntax_tree::{AstBlock, AstOutputSignalDecl, AstPragma, AstTemplateDef}, syntax::SyntaxTreeBuilder, syntax_node::CircomLanguage, }; - fn syntax_node_from_source(source: &str) -> SyntaxNode { + fn syntax_node_from_source(source: &str, scope: Scope) -> SyntaxNode { let input = Input::new(&source); - let output = Parser::parsing_with_scope(&input, Scope::Pragma); + let output = Parser::parsing_with_scope(&input, scope); // output is a tree whose node is index of token, no content of token // convert output into green node @@ -259,7 +258,7 @@ mod grammar_tests { let version = r#"2.0.1"#; let source = format!(r#"pragma circom {};"#, version); - let syntax = syntax_node_from_source(&source); + let syntax = syntax_node_from_source(&source, Scope::Pragma); // cast syntax node into ast node to retrieve more information let pragma = AstPragma::cast(syntax).expect("Can not cast syntax node into ast pragma"); @@ -290,7 +289,7 @@ mod grammar_tests { }"#; - let syntax = syntax_node_from_source(&SOURCE); + let syntax = syntax_node_from_source(&SOURCE, Scope::Template); // cast syntax node into ast node to retrieve more information let template = @@ -329,8 +328,12 @@ mod grammar_tests { insta::assert_yaml_snapshot!(last_param, @"QQ"); // statements - let statements = template.statements().unwrap().statement_list(); + let statements = template.statements().unwrap(); + let output_signal = statements.find_children::(); + println!("{:?}", output_signal); + let statements: Vec = statements + .statement_list() .into_iter() .map(|statement| statement.syntax().text().to_string()) .collect(); @@ -372,7 +375,7 @@ mod grammar_tests { out <== comp[N-2].out; }"#; - let syntax = syntax_node_from_source(&source); + let syntax = syntax_node_from_source(&source, Scope::Block); // cast syntax node into ast node to retrieve more information let block = AstBlock::cast(syntax).expect("Can not cast syntax node into ast block"); From cafff028e7e9528b4d07ce64f9f5d8f2455d8b8e Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Fri, 27 Dec 2024 21:03:15 +0700 Subject: [PATCH 24/59] add snapshot guild --- SNAPSHOT_TEST.md | 11 +++++++++++ crates/syntax/src/syntax.rs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 SNAPSHOT_TEST.md diff --git a/SNAPSHOT_TEST.md b/SNAPSHOT_TEST.md new file mode 100644 index 0000000..304166f --- /dev/null +++ b/SNAPSHOT_TEST.md @@ -0,0 +1,11 @@ +# Snapshot Test + +* Run all tests: + ``` + cargo test + ``` + +* Review snapshot changes + ``` + cargo insta review + ``` \ No newline at end of file diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index a2fe669..8e194e0 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -304,7 +304,7 @@ mod grammar_tests { .syntax() .text() .to_string(); - insta::assert_yaml_snapshot!(name, @"MultiplierN"); + insta::assert_yaml_snapshot!(name, @r###"" MultiplierN""###); // parameter list let first_param = template From 03da99a9dcd3c24258d3929ef329ca5365b4f4d6 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Fri, 27 Dec 2024 23:23:54 +0700 Subject: [PATCH 25/59] add some combine arithmetic operators --- crates/parser/src/token_kind.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 9eba89c..62b28bb 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -67,6 +67,26 @@ pub enum TokenKind { Semicolon, #[token(",")] Comma, + // TODO: review + #[token("++")] + UnitInc, + #[token("--")] + UnitDec, + #[token("+=")] + AddAssign, + #[token("-=")] + SubAssign, + #[token("/=")] + DivAssign, + #[token(r"\=")] + IntDivAssign, + #[token("%=")] + ModAssign, + #[token("*=")] + MulAssign, + #[token("**=")] + PowerAssign, + // end review #[token("=")] Assign, #[token("===")] @@ -227,12 +247,18 @@ impl TokenKind { Self::Add | Self::Sub => Some((92, 93)), Self::Mul | Self::Div | Self::IntDiv | Self::Mod => Some((94, 95)), Self::Power => Some((96, 97)), + // TODO: review + Self::AddAssign | Self::SubAssign => Some((98,99)), + Self::MulAssign | Self::DivAssign | Self::IntDivAssign | Self::ModAssign => Some((100,101)), + Self::PowerAssign => Some((102,103)), _ => None, } } pub fn prefix(self) -> Option { match self { + // TODO: review UnitDec, UnitInc + Self::UnitDec | Self::UnitInc => Some(101), Self::Sub => Some(100), Self::Not => Some(99), Self::BitNot => Some(98), @@ -242,6 +268,8 @@ impl TokenKind { pub fn postfix(self) -> Option { match self { + // TODO: review UnitDec, UnitInc + Self::UnitDec | Self::UnitInc => Some(202), Self::Dot => Some(200), Self::LBracket => Some(201), _ => None, From 7792a96c5d0a556a9b57ee638afe42267a0d92fe Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Fri, 27 Dec 2024 23:25:34 +0700 Subject: [PATCH 26/59] error report in expect and expect_any --- crates/parser/src/event.rs | 3 ++- crates/parser/src/output.rs | 8 ++++++++ crates/parser/src/parser.rs | 19 +++++++++++++------ crates/syntax/src/syntax.rs | 27 ++++++++++++++++++++------- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/crates/parser/src/event.rs b/crates/parser/src/event.rs index 16996b9..bd9c2cc 100644 --- a/crates/parser/src/event.rs +++ b/crates/parser/src/event.rs @@ -1,8 +1,9 @@ use crate::token_kind::TokenKind; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub enum Event { Open { kind: TokenKind }, Close, TokenPosition(usize), + ErrorReport(String), } diff --git a/crates/parser/src/output.rs b/crates/parser/src/output.rs index 271c2c3..b594a3e 100644 --- a/crates/parser/src/output.rs +++ b/crates/parser/src/output.rs @@ -3,6 +3,7 @@ use crate::{event::Event, token_kind::TokenKind}; #[derive(Debug)] pub enum Child { Token(usize), // position of token, + Error(String), Tree(Tree), } @@ -58,6 +59,13 @@ impl From> for Output { .children .push(Child::Token(*token)); } + Event::ErrorReport(error) => { + stack + .last_mut() + .unwrap() + .children + .push(Child::Error(error.clone())); + } } } } diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index 2fbe667..b121669 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -88,6 +88,15 @@ impl<'a> Parser<'a> { } self.close(m, TokenKind::Error); } + + pub fn error_report(&mut self, error: String) { + let m = self.open(); + + let token = Event::ErrorReport(error); + self.events.push(token); + + self.close(m, TokenKind::Error); + } } impl<'a> Parser<'a> { @@ -170,19 +179,17 @@ impl<'a> Parser<'a> { if kinds.contains(&kind) { self.advance(); } else { - // error report - // println!("expect {:?} but got {:?}", kinds, kind); + let error = format!("expect {:?} but got {:?}", kinds, kind); + self.error_report(error); } } pub fn expect(&mut self, kind: TokenKind) { - let _current = self.current(); - if self.at(kind) { self.advance(); } else { - // TODO - // advance_with_error: ("expect {:?} but got {:?}", kind, current); + let error = format!("expect {:?} but got {:?}", kind, self.current()); + self.error_report(error); } } diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 8e194e0..1d65867 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -1,6 +1,7 @@ use parser::input::Input; use parser::output::{Child, Output}; use parser::parser::Parser; +use parser::token_kind::TokenKind; use rowan::{GreenNode, GreenNodeBuilder}; use crate::syntax_node::SyntaxNode; @@ -30,6 +31,14 @@ impl<'a> SyntaxTreeBuilder<'a> { self.builder.finish_node(); } Child::Tree(child_tree) => self.build_rec(child_tree), + Child::Error(error) => { + let token_kind = TokenKind::Error; + let token_value = error.as_str(); + + self.builder.start_node(token_kind.into()); + self.builder.token(token_kind.into(), token_value); + self.builder.finish_node(); + } } } @@ -113,6 +122,10 @@ mod tests { .function_list() .iter() .map(|function| { + println!( + "function body:\n{:?}", + function.body().unwrap().syntax().text().to_string() + ); function .function_name() .unwrap() @@ -177,11 +190,11 @@ mod tests { let pragma = pragma_string_from_ast(&ast); insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - let template_names = template_names_from_ast(&ast); - insta::assert_yaml_snapshot!("syntax_test_2_templates", template_names); - let function_names = function_names_from_ast(&ast); insta::assert_yaml_snapshot!("syntax_test_2_functions", function_names); + + let template_names = template_names_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_2_templates", template_names); } #[test] @@ -228,13 +241,13 @@ mod tests { #[cfg(test)] mod grammar_tests { - use parser::{grammar::entry::Scope, input::Input, parser::Parser}; - use rowan::{ast::AstNode, SyntaxNode}; use crate::{ abstract_syntax_tree::{AstBlock, AstOutputSignalDecl, AstPragma, AstTemplateDef}, syntax::SyntaxTreeBuilder, syntax_node::CircomLanguage, }; + use parser::{grammar::entry::Scope, input::Input, parser::Parser}; + use rowan::{ast::AstNode, SyntaxNode}; fn syntax_node_from_source(source: &str, scope: Scope) -> SyntaxNode { let input = Input::new(&source); @@ -304,7 +317,7 @@ mod grammar_tests { .syntax() .text() .to_string(); - insta::assert_yaml_snapshot!(name, @r###"" MultiplierN""###); + insta::assert_yaml_snapshot!(name, @"MultiplierN"); // parameter list let first_param = template @@ -331,7 +344,7 @@ mod grammar_tests { let statements = template.statements().unwrap(); let output_signal = statements.find_children::(); println!("{:?}", output_signal); - + let statements: Vec = statements .statement_list() .into_iter() From 6ac9ac990ef9317eafc6cee33e44fa3c72513808 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Fri, 27 Dec 2024 23:30:44 +0700 Subject: [PATCH 27/59] update snapshot for combine operators --- .../snapshots/parser__input__tests__test_function.snap | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/crates/parser/src/snapshots/parser__input__tests__test_function.snap b/crates/parser/src/snapshots/parser__input__tests__test_function.snap index dd235e2..39cbb10 100644 --- a/crates/parser/src/snapshots/parser__input__tests__test_function.snap +++ b/crates/parser/src/snapshots/parser__input__tests__test_function.snap @@ -49,15 +49,13 @@ kind: - EndLine - WhiteSpace - Identifier - - Add - - Add + - UnitInc - Semicolon - EndLine - WhiteSpace - Identifier - WhiteSpace - - Mul - - Assign + - MulAssign - WhiteSpace - Number - Semicolon @@ -168,8 +166,6 @@ position: - start: 99 end: 100 - start: 100 - end: 101 - - start: 101 end: 102 - start: 102 end: 103 @@ -182,8 +178,6 @@ position: - start: 117 end: 118 - start: 118 - end: 119 - - start: 119 end: 120 - start: 120 end: 121 From ec73df88356ef33167bc043ad7f2c91fc0ee7962 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sat, 28 Dec 2024 14:31:30 +0700 Subject: [PATCH 28/59] update snapshot test --- .../syntax__syntax__tests__syntax_test_2_functions.snap | 2 +- .../syntax__syntax__tests__syntax_test_2_templates.snap | 2 +- .../syntax__syntax__tests__syntax_test_5_templates.snap | 2 +- .../syntax__syntax__tests__syntax_test_6_templates.snap | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_functions.snap b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_functions.snap index 49ea709..0913804 100644 --- a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_functions.snap +++ b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_functions.snap @@ -2,4 +2,4 @@ source: crates/syntax/src/syntax.rs expression: function_names --- -- "nbits" +- nbits diff --git a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_templates.snap b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_templates.snap index 03a1b69..db61c87 100644 --- a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_templates.snap +++ b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_2_templates.snap @@ -2,4 +2,4 @@ source: crates/syntax/src/syntax.rs expression: template_names --- -- "BinSum" +- BinSum diff --git a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_5_templates.snap b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_5_templates.snap index 53cde17..8050901 100644 --- a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_5_templates.snap +++ b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_5_templates.snap @@ -2,4 +2,4 @@ source: crates/syntax/src/syntax.rs expression: template_names --- -- "Multiplier2" +- Multiplier2 diff --git a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_6_templates.snap b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_6_templates.snap index 53cde17..8050901 100644 --- a/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_6_templates.snap +++ b/crates/syntax/src/snapshots/syntax__syntax__tests__syntax_test_6_templates.snap @@ -2,4 +2,4 @@ source: crates/syntax/src/syntax.rs expression: template_names --- -- "Multiplier2" +- Multiplier2 From 5bdda2fad69a2c84500f1b7da838ebc0fd917018 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sat, 28 Dec 2024 14:35:14 +0700 Subject: [PATCH 29/59] fix wrap trivial tokens before open a tree --- crates/parser/src/parser.rs | 37 ++++++++++++++++++++++++------------- crates/syntax/src/syntax.rs | 4 ---- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index b121669..34a2f64 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -28,7 +28,29 @@ pub enum ParserError { } impl<'a> Parser<'a> { + pub fn wrap_trivial_tokens(&mut self) -> TokenKind { + loop { + let kind = self.input.kind_of(self.pos); + + if kind.is_trivial() == false { + return kind; + } + + self.events.push(Event::Open { kind }); + + self.fuel.set(256); + self.events.push(Event::TokenPosition(self.pos)); + self.skip(); + + self.events.push(Event::Close); + } + } + pub fn open(&mut self) -> Marker { + if self.events.len() > 0 { + self.wrap_trivial_tokens(); + } + let marker = Marker::Open(self.events.len()); self.events.push(Event::Open { kind: TokenKind::Error, @@ -119,19 +141,7 @@ impl<'a> Parser<'a> { } pub fn current(&mut self) -> TokenKind { - let mut kind: TokenKind; - loop { - kind = self.input.kind_of(self.pos); - if !kind.is_trivial() { - break; - } - - let m = self.open(); - self.advance(); - self.close(m, kind); - } - - kind + self.wrap_trivial_tokens() } pub fn next(&mut self) -> TokenKind { @@ -171,6 +181,7 @@ impl<'a> Parser<'a> { self.advance(); return true; } + false } diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 1d65867..054f39d 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -122,10 +122,6 @@ mod tests { .function_list() .iter() .map(|function| { - println!( - "function body:\n{:?}", - function.body().unwrap().syntax().text().to_string() - ); function .function_name() .unwrap() From 8e4853de21093dc348708f3ff50dc36d1e725214 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sat, 28 Dec 2024 15:13:14 +0700 Subject: [PATCH 30/59] update template happy test --- crates/syntax/src/syntax.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 054f39d..a2f9f39 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -348,17 +348,21 @@ mod grammar_tests { .collect(); insta::assert_yaml_snapshot!("template_happy_test_statements", statements); - // // input signal - // println!("find_input_signal: {:?}", template.find_input_signal()); + // input signal + let input_signal = template.find_input_signal("in").unwrap().syntax().text().to_string(); + insta::assert_yaml_snapshot!(input_signal, @"signal input in[N];"); - // // output signal - // println!("find_output_signal: {:?}", template.find_output_signal()); + // output signal + let output_signal = template.find_output_signal("out").unwrap().syntax().text().to_string(); + insta::assert_yaml_snapshot!(output_signal, @"signal output out;"); - // // internal signal - // println!("find_internal_signal: {:?}", template.find_internal_signal()); + // internal signal + let internal_signal = template.find_internal_signal("in").is_none(); + insta::assert_yaml_snapshot!(internal_signal, @"true"); - // // component - // println!("find_component: {:?}", template.find_component()); + // component + let component = template.find_component("comp").unwrap().syntax().text().to_string(); + insta::assert_yaml_snapshot!(component, @"component comp[N-1];"); } #[test] From bb95297c47d898881305384c17c76362e678367d Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sat, 28 Dec 2024 17:43:19 +0700 Subject: [PATCH 31/59] add operators into token kinds --- crates/lsp/src/handler/goto_definition.rs | 2 +- crates/parser/src/token_kind.rs | 180 +++++++++++++--------- 2 files changed, 105 insertions(+), 77 deletions(-) diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 4cba681..10ef0ed 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -228,7 +228,7 @@ template Y() { let file = FileDB::create(&source, Url::from_file_path(Path::new("/tmp")).unwrap()); let syntax_node = SyntaxTreeBuilder::syntax_tree(&source); - + if let Some(program_ast) = AstCircomProgram::cast(syntax_node) { for template in program_ast.template_list() { println!("{template:?}"); diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 62b28bb..1265324 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -5,24 +5,29 @@ use serde::Serialize; #[allow(non_camel_case_types)] #[repr(u16)] pub enum TokenKind { + // Error #[error] Error = 0, + // Comments #[regex(r"//[^\n]*")] CommentLine, #[token("/*")] CommentBlockOpen, #[token("*/")] CommentBlockClose, + // Trivial #[regex("[ \t]+")] WhiteSpace, #[regex("[\n]")] EndLine, + // Circom #[token("pragma")] Pragma, #[token("circom")] Circom, #[regex("2.[0-9].[0-9]")] Version, + // Literals #[regex("[0-9]+")] Number, #[regex("[$_]*[a-zA-Z][a-zA-Z0-9_$]*")] @@ -31,26 +36,7 @@ pub enum TokenKind { CircomString, #[token("template")] TemplateKw, - #[token("function")] - FunctionKw, - #[token("component")] - ComponentKw, - #[token("main")] - MainKw, - #[token("public")] - PublicKw, - #[token("signal")] - SignalKw, - #[token("var")] - VarKw, - #[token("include")] - IncludeKw, - #[token("input")] - InputKw, - #[token("output")] - OutputKw, - #[token("log")] - LogKw, + // Brackets #[token("(")] LParen, #[token(")")] @@ -63,30 +49,94 @@ pub enum TokenKind { LBracket, #[token("]")] RBracket, + // Punctuation #[token(";")] Semicolon, #[token(",")] Comma, - // TODO: review - #[token("++")] - UnitInc, - #[token("--")] - UnitDec, + #[token(".")] + Dot, + // Boolean operators + #[token("&&")] + BoolAnd, + #[token("||")] + BoolOr, + #[token("!")] + Not, + // Relational operators + #[token("==")] + Equal, + #[token("!=")] + NotEqual, + #[token("<")] + LessThan, + #[token(">")] + GreaterThan, + #[token("<=")] + LessThanAndEqual, + #[token(">=")] + GreaterThanAndEqual, + // Arithmetic operators + #[token("+")] + Add, + #[token("-")] + Sub, + #[token("*")] + Mul, + #[token("**")] + Power, + #[token("/")] + Div, + #[token("\\")] + IntDiv, + #[token("%")] + Mod, + // Combined arithmetic assignment #[token("+=")] AddAssign, #[token("-=")] SubAssign, + #[token("*=")] + MulAssign, + #[token("**=")] + PowerAssign, #[token("/=")] DivAssign, #[token(r"\=")] IntDivAssign, #[token("%=")] ModAssign, - #[token("*=")] - MulAssign, - #[token("**=")] - PowerAssign, - // end review + #[token("++")] + UnitInc, + #[token("--")] + UnitDec, + // Bitwise operators + #[token("&")] + BitAnd, + #[token("|")] + BitOr, + #[token("~")] + BitNot, + #[token("^")] + BitXor, + #[token(">>")] + ShiftR, + #[token("<<")] + ShiftL, + // Combined bitwise assignments + #[token("&=")] + BitAndAssign, + #[token("|=")] + BitOrAssign, + #[token("~=")] + BitNotAssign, + #[token("^=")] + BitXorAssign, + #[token(">>=")] + ShiftRAssign, + #[token("<<=")] + ShiftLAssign, + // Assign #[token("=")] Assign, #[token("===")] @@ -99,56 +149,33 @@ pub enum TokenKind { RAssignSignal, #[token("<==")] RAssignConstraintSignal, - #[token("+")] - Add, - #[token("-")] - Sub, - #[token("/")] - Div, - #[token("*")] - Mul, - #[token("!")] - Not, - #[token("~")] - BitNot, - #[token("**")] - Power, - #[token("\\")] - IntDiv, - #[token("%")] - Mod, - #[token("<<")] - ShiftL, - #[token(">>")] - ShiftR, - #[token("&")] - BitAnd, - #[token("|")] - BitOr, - #[token("^")] - BitXor, - #[token("==")] - Equal, - #[token("!=")] - NotEqual, - #[token("<")] - LessThan, - #[token(">")] - GreaterThan, - #[token("<=")] - LessThanAndEqual, - #[token(">=")] - GreaterThanAndEqual, - #[token("&&")] - BoolAnd, - #[token("||")] - BoolOr, + // Conditional expressions #[token("?")] MarkQuestion, #[token(":")] Colon, - #[token(".")] - Dot, + // Keywords + #[token("function")] + FunctionKw, + #[token("component")] + ComponentKw, + #[token("main")] + MainKw, + #[token("public")] + PublicKw, + #[token("signal")] + SignalKw, + #[token("var")] + VarKw, + #[token("include")] + IncludeKw, + #[token("input")] + InputKw, + #[token("output")] + OutputKw, + #[token("log")] + LogKw, + // Statement keywords #[token("if")] IfKw, #[token("else")] @@ -161,6 +188,7 @@ pub enum TokenKind { ReturnKw, #[token("assert")] AssertKw, + // Complex token kind ForLoop, AssignStatement, CircomProgram, From 97bb6899c806c5996525ec82b20092884ce5fdab Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 10:59:12 +0700 Subject: [PATCH 32/59] add operators test --- crates/parser/src/input.rs | 30 ++ .../parser__input__tests__test_operators.snap | 391 ++++++++++++++++++ crates/parser/src/token_kind.rs | 4 +- 3 files changed, 423 insertions(+), 2 deletions(-) create mode 100644 crates/parser/src/snapshots/parser__input__tests__test_operators.snap diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index c57648e..0289561 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -138,4 +138,34 @@ mod tests { }"#; test(source, "test_function"); } + + #[test] + fn test_operators() { + let source = r#" + ({[]}) + ;.,: + && & + || | + != ! + === == = + --> ==> + <-- <== + <= < + >= > + ++ += + + -- -= - + **= ** + * *= + / /= + \ \= + % %= + ^ ^= + ~ ~= + >> >>= + << <<= + & &= + | |= + }"#; + test(source, "test_operators"); + } } diff --git a/crates/parser/src/snapshots/parser__input__tests__test_operators.snap b/crates/parser/src/snapshots/parser__input__tests__test_operators.snap new file mode 100644 index 0000000..1366b66 --- /dev/null +++ b/crates/parser/src/snapshots/parser__input__tests__test_operators.snap @@ -0,0 +1,391 @@ +--- +source: crates/parser/src/input.rs +expression: input +--- +kind: + - EndLine + - WhiteSpace + - LParen + - LCurly + - LBracket + - RBracket + - RCurly + - RParen + - EndLine + - WhiteSpace + - Semicolon + - Dot + - Comma + - Colon + - EndLine + - WhiteSpace + - BoolAnd + - WhiteSpace + - BitAnd + - EndLine + - WhiteSpace + - BoolOr + - WhiteSpace + - BitOr + - EndLine + - WhiteSpace + - NotEqual + - WhiteSpace + - Not + - EndLine + - WhiteSpace + - EqualSignal + - WhiteSpace + - Equal + - WhiteSpace + - Assign + - EndLine + - WhiteSpace + - LAssignSignal + - WhiteSpace + - LAssignContraintSignal + - EndLine + - WhiteSpace + - RAssignSignal + - WhiteSpace + - RAssignConstraintSignal + - EndLine + - WhiteSpace + - LessThanAndEqual + - WhiteSpace + - LessThan + - EndLine + - WhiteSpace + - GreaterThanAndEqual + - WhiteSpace + - GreaterThan + - EndLine + - WhiteSpace + - UnitInc + - WhiteSpace + - AddAssign + - WhiteSpace + - Add + - EndLine + - WhiteSpace + - UnitDec + - WhiteSpace + - SubAssign + - WhiteSpace + - Sub + - EndLine + - WhiteSpace + - PowerAssign + - WhiteSpace + - Power + - EndLine + - WhiteSpace + - Mul + - WhiteSpace + - MulAssign + - EndLine + - WhiteSpace + - Div + - WhiteSpace + - DivAssign + - EndLine + - WhiteSpace + - IntDiv + - WhiteSpace + - IntDivAssign + - EndLine + - WhiteSpace + - Mod + - WhiteSpace + - ModAssign + - EndLine + - WhiteSpace + - BitXor + - WhiteSpace + - BitXorAssign + - EndLine + - WhiteSpace + - BitNot + - WhiteSpace + - BitNotAssign + - EndLine + - WhiteSpace + - ShiftR + - WhiteSpace + - ShiftRAssign + - EndLine + - WhiteSpace + - ShiftL + - WhiteSpace + - ShiftLAssign + - EndLine + - WhiteSpace + - BitAnd + - WhiteSpace + - BitAndAssign + - EndLine + - WhiteSpace + - BitOr + - WhiteSpace + - BitOrAssign + - EndLine + - WhiteSpace + - RCurly +source: "\n ({[]})\n ;.,:\n && &\n || |\n != !\n === == =\n --> ==>\n <-- <==\n <= <\n >= >\n ++ += +\n -- -= -\n **= **\n * *=\n / /=\n \\ \\=\n % %=\n ^ ^=\n ~ ~=\n >> >>=\n << <<=\n & &=\n | |=\n }" +position: + - start: 0 + end: 1 + - start: 1 + end: 9 + - start: 9 + end: 10 + - start: 10 + end: 11 + - start: 11 + end: 12 + - start: 12 + end: 13 + - start: 13 + end: 14 + - start: 14 + end: 15 + - start: 15 + end: 16 + - start: 16 + end: 24 + - start: 24 + end: 25 + - start: 25 + end: 26 + - start: 26 + end: 27 + - start: 27 + end: 28 + - start: 28 + end: 29 + - start: 29 + end: 37 + - start: 37 + end: 39 + - start: 39 + end: 40 + - start: 40 + end: 41 + - start: 41 + end: 42 + - start: 42 + end: 50 + - start: 50 + end: 52 + - start: 52 + end: 53 + - start: 53 + end: 54 + - start: 54 + end: 55 + - start: 55 + end: 63 + - start: 63 + end: 65 + - start: 65 + end: 66 + - start: 66 + end: 67 + - start: 67 + end: 68 + - start: 68 + end: 76 + - start: 76 + end: 79 + - start: 79 + end: 80 + - start: 80 + end: 82 + - start: 82 + end: 83 + - start: 83 + end: 84 + - start: 84 + end: 85 + - start: 85 + end: 93 + - start: 93 + end: 96 + - start: 96 + end: 97 + - start: 97 + end: 100 + - start: 100 + end: 101 + - start: 101 + end: 109 + - start: 109 + end: 112 + - start: 112 + end: 113 + - start: 113 + end: 116 + - start: 116 + end: 117 + - start: 117 + end: 125 + - start: 125 + end: 127 + - start: 127 + end: 128 + - start: 128 + end: 129 + - start: 129 + end: 130 + - start: 130 + end: 138 + - start: 138 + end: 140 + - start: 140 + end: 141 + - start: 141 + end: 142 + - start: 142 + end: 143 + - start: 143 + end: 151 + - start: 151 + end: 153 + - start: 153 + end: 154 + - start: 154 + end: 156 + - start: 156 + end: 157 + - start: 157 + end: 158 + - start: 158 + end: 159 + - start: 159 + end: 167 + - start: 167 + end: 169 + - start: 169 + end: 170 + - start: 170 + end: 172 + - start: 172 + end: 173 + - start: 173 + end: 174 + - start: 174 + end: 175 + - start: 175 + end: 183 + - start: 183 + end: 186 + - start: 186 + end: 187 + - start: 187 + end: 189 + - start: 189 + end: 190 + - start: 190 + end: 198 + - start: 198 + end: 199 + - start: 199 + end: 200 + - start: 200 + end: 202 + - start: 202 + end: 203 + - start: 203 + end: 211 + - start: 211 + end: 212 + - start: 212 + end: 213 + - start: 213 + end: 215 + - start: 215 + end: 216 + - start: 216 + end: 224 + - start: 224 + end: 225 + - start: 225 + end: 226 + - start: 226 + end: 228 + - start: 228 + end: 229 + - start: 229 + end: 237 + - start: 237 + end: 238 + - start: 238 + end: 239 + - start: 239 + end: 241 + - start: 241 + end: 242 + - start: 242 + end: 250 + - start: 250 + end: 251 + - start: 251 + end: 252 + - start: 252 + end: 254 + - start: 254 + end: 255 + - start: 255 + end: 263 + - start: 263 + end: 264 + - start: 264 + end: 265 + - start: 265 + end: 267 + - start: 267 + end: 268 + - start: 268 + end: 276 + - start: 276 + end: 278 + - start: 278 + end: 279 + - start: 279 + end: 282 + - start: 282 + end: 283 + - start: 283 + end: 291 + - start: 291 + end: 293 + - start: 293 + end: 294 + - start: 294 + end: 297 + - start: 297 + end: 298 + - start: 298 + end: 306 + - start: 306 + end: 307 + - start: 307 + end: 308 + - start: 308 + end: 310 + - start: 310 + end: 311 + - start: 311 + end: 319 + - start: 319 + end: 320 + - start: 320 + end: 321 + - start: 321 + end: 323 + - start: 323 + end: 324 + - start: 324 + end: 328 + - start: 328 + end: 329 diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 1265324..9f1e3cb 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -34,8 +34,6 @@ pub enum TokenKind { Identifier, #[regex(r#""[^"]*""#)] CircomString, - #[token("template")] - TemplateKw, // Brackets #[token("(")] LParen, @@ -155,6 +153,8 @@ pub enum TokenKind { #[token(":")] Colon, // Keywords + #[token("template")] + TemplateKw, #[token("function")] FunctionKw, #[token("component")] From 179f6bc77c7fa9ec3246c3852b311bb10c5bd55b Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 12:37:07 +0700 Subject: [PATCH 33/59] re-priority token kinds --- crates/parser/src/token_kind.rs | 98 +++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 28 deletions(-) diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 9f1e3cb..21d3625 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -47,7 +47,7 @@ pub enum TokenKind { LBracket, #[token("]")] RBracket, - // Punctuation + // Punctuation #[token(";")] Semicolon, #[token(",")] @@ -121,7 +121,7 @@ pub enum TokenKind { ShiftR, #[token("<<")] ShiftL, - // Combined bitwise assignments + // Combined bitwise assignments #[token("&=")] BitAndAssign, #[token("|=")] @@ -254,52 +254,94 @@ impl From for rowan::SyntaxKind { } impl TokenKind { + // a + 10 --> a and 10 are literals pub fn is_literal(self) -> bool { matches!(self, Self::Number | Self::Identifier) } + // these tokens have the lowest priority + // infix_operator + // eg: a + b --> + is an infix token pub fn infix(self) -> Option<(u16, u16)> { match self { - Self::BoolOr => Some((78, 79)), - Self::BoolAnd => Some((80, 81)), - Self::Equal - | Self::NotEqual - | Self::LessThan + // arithmetic operators + Self::Power => Some((99, 100)), + Self::Mul | Self::Div | Self::IntDiv | Self::Mod => Some((94, 95)), + Self::Add | Self::Sub => Some((89, 90)), + + // shift bitwise operators + Self::ShiftL | Self::ShiftR => Some((84, 85)), + + // relational operators + Self::LessThan | Self::GreaterThan | Self::LessThanAndEqual - | Self::GreaterThanAndEqual => Some((82, 83)), - Self::BitOr => Some((84, 85)), - Self::BitXor => Some((86, 87)), - Self::BitAnd => Some((88, 89)), - Self::ShiftL | Self::ShiftR => Some((90, 91)), - Self::Add | Self::Sub => Some((92, 93)), - Self::Mul | Self::Div | Self::IntDiv | Self::Mod => Some((94, 95)), - Self::Power => Some((96, 97)), - // TODO: review - Self::AddAssign | Self::SubAssign => Some((98,99)), - Self::MulAssign | Self::DivAssign | Self::IntDivAssign | Self::ModAssign => Some((100,101)), - Self::PowerAssign => Some((102,103)), + | Self::GreaterThanAndEqual => Some((79, 80)), + Self::Equal + | Self::NotEqual => Some((74, 75)), + + // other bitwise operators + Self::BitAnd => Some((69, 70)), + Self::BitXor => Some((64, 65)), // exclusive or + Self::BitOr => Some((59, 60)), + + // boolean operators + Self::BoolAnd => Some((54, 55)), + Self::BoolOr => Some((49, 50)), + + // TODO: how about conditional operation ( ? : ) + // associativity: right to left [ a ? b : c --> ??? ] + + // associativity: right to left [ a = b = c --> a = (b = c) ] + // assignment operators + Self::Assign + // bitwise asignment operators + | Self::BitOrAssign + | Self::BitXorAssign + | Self::BitAndAssign + | Self::ShiftLAssign + | Self::ShiftRAssign + // arithmetic asignament operators + | Self::AddAssign + | Self::SubAssign + | Self::MulAssign + | Self::DivAssign + | Self::IntDivAssign + | Self::ModAssign + | Self::PowerAssign => Some((44, 45)), + + // TODO: how about comma (expression separator) + Self::Comma => Some((39, 40)), + + // not an infix operator _ => None, } } + // priority: post > pre > in + // associativity: right to left [ --!a --> --(!a) ] + // prefix_operator + // eg: -10, !a, ++a, --a pub fn prefix(self) -> Option { match self { - // TODO: review UnitDec, UnitInc - Self::UnitDec | Self::UnitInc => Some(101), - Self::Sub => Some(100), - Self::Not => Some(99), - Self::BitNot => Some(98), + Self::UnitDec | Self::UnitInc + | Self::Sub | Self::Add + | Self::Not | Self::BitNot => Some(200), + _ => None, } } + // these tokens have the highest priority + // postfix_operator + // eg: a[10], b++, c.att1 pub fn postfix(self) -> Option { match self { - // TODO: review UnitDec, UnitInc - Self::UnitDec | Self::UnitInc => Some(202), - Self::Dot => Some(200), - Self::LBracket => Some(201), + Self::LParen // function call + | Self::LBracket // array subscript + | Self::Dot // attribute access + | Self::UnitDec | Self::UnitInc => Some(300), + _ => None, } } From 40268bf3bdc2894b36ffc23b0599a8bfabb891d6 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 12:54:30 +0700 Subject: [PATCH 34/59] fix clippy check --- crates/lsp/src/handler/goto_definition.rs | 2 +- crates/parser/src/grammar/declaration.rs | 2 +- crates/parser/src/grammar/expression.rs | 2 +- crates/parser/src/grammar/statement.rs | 8 ++++---- crates/parser/src/grammar/template.rs | 2 +- crates/parser/src/input.rs | 2 +- crates/parser/src/token_kind.rs | 12 +++++++----- crates/syntax/src/syntax.rs | 23 +++++++++++++++++++---- 8 files changed, 35 insertions(+), 18 deletions(-) diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 10ef0ed..4cba681 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -228,7 +228,7 @@ template Y() { let file = FileDB::create(&source, Url::from_file_path(Path::new("/tmp")).unwrap()); let syntax_node = SyntaxTreeBuilder::syntax_tree(&source); - + if let Some(program_ast) = AstCircomProgram::cast(syntax_node) { for template in program_ast.template_list() { println!("{template:?}"); diff --git a/crates/parser/src/grammar/declaration.rs b/crates/parser/src/grammar/declaration.rs index 27471b3..c5dd125 100644 --- a/crates/parser/src/grammar/declaration.rs +++ b/crates/parser/src/grammar/declaration.rs @@ -127,4 +127,4 @@ pub(super) fn declaration(p: &mut Parser) { ComponentKw => component_declaration(p), _ => unreachable!(), } -} \ No newline at end of file +} diff --git a/crates/parser/src/grammar/expression.rs b/crates/parser/src/grammar/expression.rs index 96c85e0..4604da4 100644 --- a/crates/parser/src/grammar/expression.rs +++ b/crates/parser/src/grammar/expression.rs @@ -155,4 +155,4 @@ fn circom_expression(p: &mut Parser) { p.close(m, TenaryConditional); } } -} \ No newline at end of file +} diff --git a/crates/parser/src/grammar/statement.rs b/crates/parser/src/grammar/statement.rs index d8b75fa..84ca0a6 100644 --- a/crates/parser/src/grammar/statement.rs +++ b/crates/parser/src/grammar/statement.rs @@ -12,7 +12,7 @@ pub(super) fn statement(p: &mut Parser) { /* if (expr) -else +else */ fn if_statement(p: &mut Parser) { @@ -81,7 +81,7 @@ fn for_statement(p: &mut Parser) { p.close(m, ForLoop); } -/* +/* while () */ @@ -93,7 +93,7 @@ fn while_statement(p: &mut Parser) { statement(p); } -/* +/* assert() */ fn assert_statement(p: &mut Parser) { @@ -181,4 +181,4 @@ fn assignment_statement(p: &mut Parser) { } else { p.close(m, Error); } -} \ No newline at end of file +} diff --git a/crates/parser/src/grammar/template.rs b/crates/parser/src/grammar/template.rs index 359d774..a502365 100644 --- a/crates/parser/src/grammar/template.rs +++ b/crates/parser/src/grammar/template.rs @@ -22,4 +22,4 @@ pub fn template(p: &mut Parser) { block::block(p); p.close(m, TemplateDef); -} \ No newline at end of file +} diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index c57648e..fc555cf 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -136,6 +136,6 @@ mod tests { } return r; }"#; - test(source, "test_function"); + test(source, "test_function"); } } diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 1265324..2b2cade 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -49,7 +49,7 @@ pub enum TokenKind { LBracket, #[token("]")] RBracket, - // Punctuation + // Punctuation #[token(";")] Semicolon, #[token(",")] @@ -123,7 +123,7 @@ pub enum TokenKind { ShiftR, #[token("<<")] ShiftL, - // Combined bitwise assignments + // Combined bitwise assignments #[token("&=")] BitAndAssign, #[token("|=")] @@ -276,9 +276,11 @@ impl TokenKind { Self::Mul | Self::Div | Self::IntDiv | Self::Mod => Some((94, 95)), Self::Power => Some((96, 97)), // TODO: review - Self::AddAssign | Self::SubAssign => Some((98,99)), - Self::MulAssign | Self::DivAssign | Self::IntDivAssign | Self::ModAssign => Some((100,101)), - Self::PowerAssign => Some((102,103)), + Self::AddAssign | Self::SubAssign => Some((98, 99)), + Self::MulAssign | Self::DivAssign | Self::IntDivAssign | Self::ModAssign => { + Some((100, 101)) + } + Self::PowerAssign => Some((102, 103)), _ => None, } } diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 56816dc..ded3cc3 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -299,7 +299,7 @@ mod grammar_tests { }"#; let syntax = syntax_node_from_source(&SOURCE, Scope::Template); - + // cast syntax node into ast node to retrieve more information let template = AstTemplateDef::cast(syntax).expect("Can not cast syntax node into ast template"); @@ -349,11 +349,21 @@ mod grammar_tests { insta::assert_yaml_snapshot!("template_happy_test_statements", statements); // input signal - let input_signal = template.find_input_signal("in").unwrap().syntax().text().to_string(); + let input_signal = template + .find_input_signal("in") + .unwrap() + .syntax() + .text() + .to_string(); insta::assert_yaml_snapshot!(input_signal, @"signal input in[N];"); // output signal - let output_signal = template.find_output_signal("out").unwrap().syntax().text().to_string(); + let output_signal = template + .find_output_signal("out") + .unwrap() + .syntax() + .text() + .to_string(); insta::assert_yaml_snapshot!(output_signal, @"signal output out;"); // internal signal @@ -361,7 +371,12 @@ mod grammar_tests { insta::assert_yaml_snapshot!(internal_signal, @"true"); // component - let component = template.find_component("comp").unwrap().syntax().text().to_string(); + let component = template + .find_component("comp") + .unwrap() + .syntax() + .text() + .to_string(); insta::assert_yaml_snapshot!(component, @"component comp[N-1];"); } From 156b8729a85a14ffa0be70bf77e6020191472317 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 12:54:30 +0700 Subject: [PATCH 35/59] fix clippy check --- crates/lsp/src/handler/goto_definition.rs | 2 +- crates/parser/src/grammar/declaration.rs | 2 +- crates/parser/src/grammar/expression.rs | 2 +- crates/parser/src/grammar/statement.rs | 8 ++++---- crates/parser/src/grammar/template.rs | 2 +- crates/parser/src/input.rs | 2 +- crates/syntax/src/syntax.rs | 23 +++++++++++++++++++---- 7 files changed, 28 insertions(+), 13 deletions(-) diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 10ef0ed..4cba681 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -228,7 +228,7 @@ template Y() { let file = FileDB::create(&source, Url::from_file_path(Path::new("/tmp")).unwrap()); let syntax_node = SyntaxTreeBuilder::syntax_tree(&source); - + if let Some(program_ast) = AstCircomProgram::cast(syntax_node) { for template in program_ast.template_list() { println!("{template:?}"); diff --git a/crates/parser/src/grammar/declaration.rs b/crates/parser/src/grammar/declaration.rs index 27471b3..c5dd125 100644 --- a/crates/parser/src/grammar/declaration.rs +++ b/crates/parser/src/grammar/declaration.rs @@ -127,4 +127,4 @@ pub(super) fn declaration(p: &mut Parser) { ComponentKw => component_declaration(p), _ => unreachable!(), } -} \ No newline at end of file +} diff --git a/crates/parser/src/grammar/expression.rs b/crates/parser/src/grammar/expression.rs index 96c85e0..4604da4 100644 --- a/crates/parser/src/grammar/expression.rs +++ b/crates/parser/src/grammar/expression.rs @@ -155,4 +155,4 @@ fn circom_expression(p: &mut Parser) { p.close(m, TenaryConditional); } } -} \ No newline at end of file +} diff --git a/crates/parser/src/grammar/statement.rs b/crates/parser/src/grammar/statement.rs index d8b75fa..84ca0a6 100644 --- a/crates/parser/src/grammar/statement.rs +++ b/crates/parser/src/grammar/statement.rs @@ -12,7 +12,7 @@ pub(super) fn statement(p: &mut Parser) { /* if (expr) -else +else */ fn if_statement(p: &mut Parser) { @@ -81,7 +81,7 @@ fn for_statement(p: &mut Parser) { p.close(m, ForLoop); } -/* +/* while () */ @@ -93,7 +93,7 @@ fn while_statement(p: &mut Parser) { statement(p); } -/* +/* assert() */ fn assert_statement(p: &mut Parser) { @@ -181,4 +181,4 @@ fn assignment_statement(p: &mut Parser) { } else { p.close(m, Error); } -} \ No newline at end of file +} diff --git a/crates/parser/src/grammar/template.rs b/crates/parser/src/grammar/template.rs index 359d774..a502365 100644 --- a/crates/parser/src/grammar/template.rs +++ b/crates/parser/src/grammar/template.rs @@ -22,4 +22,4 @@ pub fn template(p: &mut Parser) { block::block(p); p.close(m, TemplateDef); -} \ No newline at end of file +} diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index 0289561..f22d611 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -136,7 +136,7 @@ mod tests { } return r; }"#; - test(source, "test_function"); + test(source, "test_function"); } #[test] diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 56816dc..ded3cc3 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -299,7 +299,7 @@ mod grammar_tests { }"#; let syntax = syntax_node_from_source(&SOURCE, Scope::Template); - + // cast syntax node into ast node to retrieve more information let template = AstTemplateDef::cast(syntax).expect("Can not cast syntax node into ast template"); @@ -349,11 +349,21 @@ mod grammar_tests { insta::assert_yaml_snapshot!("template_happy_test_statements", statements); // input signal - let input_signal = template.find_input_signal("in").unwrap().syntax().text().to_string(); + let input_signal = template + .find_input_signal("in") + .unwrap() + .syntax() + .text() + .to_string(); insta::assert_yaml_snapshot!(input_signal, @"signal input in[N];"); // output signal - let output_signal = template.find_output_signal("out").unwrap().syntax().text().to_string(); + let output_signal = template + .find_output_signal("out") + .unwrap() + .syntax() + .text() + .to_string(); insta::assert_yaml_snapshot!(output_signal, @"signal output out;"); // internal signal @@ -361,7 +371,12 @@ mod grammar_tests { insta::assert_yaml_snapshot!(internal_signal, @"true"); // component - let component = template.find_component("comp").unwrap().syntax().text().to_string(); + let component = template + .find_component("comp") + .unwrap() + .syntax() + .text() + .to_string(); insta::assert_yaml_snapshot!(component, @"component comp[N-1];"); } From d18fba0921772711bf835e41c06fa2882464e14b Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 13:06:44 +0700 Subject: [PATCH 36/59] rebase add-token-kinds --- crates/lsp/src/handler/goto_definition.rs | 526 +++++------ crates/parser/src/grammar/declaration.rs | 260 +++--- crates/parser/src/grammar/expression.rs | 316 +++---- crates/parser/src/grammar/statement.rs | 368 ++++---- crates/parser/src/grammar/template.rs | 50 +- .../parser__input__tests__test_operators.snap | 782 ++++++++-------- crates/parser/src/token_kind.rs | 718 +++++++-------- crates/syntax/src/syntax.rs | 838 +++++++++--------- 8 files changed, 1929 insertions(+), 1929 deletions(-) diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 4cba681..b02121b 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -1,263 +1,263 @@ -use lsp_types::Location; -use lsp_types::Position; -use lsp_types::Range; -use lsp_types::Url; -use parser::token_kind::TokenKind; -use rowan::ast::AstNode; -use rowan::SyntaxText; - -use syntax::abstract_syntax_tree::AstComponentCall; -use syntax::abstract_syntax_tree::AstInclude; -use syntax::abstract_syntax_tree::AstTemplateDef; -use syntax::abstract_syntax_tree::AstTemplateName; -use syntax::abstract_syntax_tree::{AstCircomProgram, AstComponentDecl}; -use syntax::syntax_node::SyntaxNode; -use syntax::syntax_node::SyntaxToken; - -use crate::database::{FileDB, SemanticData, TokenId}; - -pub fn lookup_node_wrap_token(ast_type: TokenKind, token: &SyntaxToken) -> Option { - let mut p = token.parent(); - while let Some(t) = p { - if t.kind() == ast_type { - return Some(t); - } - p = t.parent(); - } - None -} - -pub fn lookup_token_at_postion( - file: &FileDB, - ast: &AstCircomProgram, - position: Position, -) -> Option { - let off_set = file.off_set(position); - ast.syntax().token_at_offset(off_set).find_map(|token| { - let kind = token.kind(); - - if kind == TokenKind::Identifier { - return Some(token); - } - - if kind == TokenKind::CircomString { - return Some(token); - } - None - }) -} - -pub fn lookup_component(template: &AstTemplateDef, text: SyntaxText) -> Option { - if let Some(statements) = template.statements() { - for component in statements.find_children::() { - if let Some(iden) = component.component_identifier() { - if iden.name().unwrap().syntax().text() == text { - return component.template(); - } - } - } - } - None -} - -pub fn jump_to_lib(file: &FileDB, token: &SyntaxToken) -> Vec { - if let Some(include_lib) = lookup_node_wrap_token(TokenKind::IncludeKw, token) { - if let Some(ast_include) = AstInclude::cast(include_lib) { - if let Some(abs_lib_ans) = ast_include.lib() { - let lib_path = file - .get_path() - .parent() - .unwrap() - .join(abs_lib_ans.value()) - .clone(); - let lib_url = Url::from_file_path(lib_path.clone()).unwrap(); - return vec![Location::new(lib_url, Range::default())]; - } - } - } - - Vec::new() -} - -pub fn lookup_definition( - file: &FileDB, - ast: &AstCircomProgram, - semantic_data: &SemanticData, - token: &SyntaxToken, -) -> Vec { - let template_list = ast.template_list(); - - let mut res = Vec::new(); - - if token.kind() == TokenKind::CircomString { - return jump_to_lib(file, token); - } - - let mut signal_outside = false; - - if let Some(component_call) = lookup_node_wrap_token(TokenKind::ComponentCall, token) { - // find template called. - if let Some(ast_component_call) = AstComponentCall::cast(component_call) { - if let Some(signal) = ast_component_call.signal() { - if signal.syntax().text() == token.text() { - signal_outside = true; - // lookup template of componenet - if let Some(current_template) = - lookup_node_wrap_token(TokenKind::TemplateDef, token) - { - if let Some(ast_template_name) = lookup_component( - &AstTemplateDef::cast(current_template).unwrap(), - ast_component_call.component_name().unwrap().syntax().text(), - ) { - if let Some(other_template) = - ast.get_template_by_name(&ast_template_name) - { - let template_id = other_template.syntax().token_id(); - if let Some(semantic) = - semantic_data.template_data_semantic.get(&template_id) - { - if let Some(tmp) = - semantic.signal.0.get(&signal.syntax().token_id()) - { - res.extend(tmp) - } - } - } - } - } - } - } - } - } - - if !signal_outside { - for template in template_list { - let template_name = template.name().unwrap(); - if template_name.name().unwrap().syntax().text() == token.text() { - let range = file.range(template.syntax()); - res.push(range); - } - - if !template - .syntax() - .text_range() - .contains_range(token.text_range()) - { - continue; - } - - let template_id = template.syntax().token_id(); - - if let Some(data) = semantic_data.lookup_signal(template_id, token) { - res.extend(data); - } - - if let Some(data) = semantic_data.lookup_variable(template_id, token) { - res.extend(data); - } - - if let Some(component_decl) = semantic_data.lookup_component(template_id, token) { - res.extend(component_decl); - } - } - } - - res.into_iter() - .map(|range| Location::new(file.file_path.clone(), range)) - .collect() -} - -#[cfg(test)] -mod tests { - use std::path::Path; - - use lsp_types::Url; - use parser::token_kind::TokenKind; - use rowan::ast::AstNode; - use syntax::{ - abstract_syntax_tree::{AstCircomProgram, AstInputSignalDecl}, - syntax::SyntaxTreeBuilder, - }; - - use crate::{database::FileDB, handler::goto_definition::lookup_node_wrap_token}; - - use super::lookup_token_at_postion; - - #[test] - fn goto_decl_test() { - let source = r#" - pragma circom 2.0.0; - - template X() { - signal x = 10; - signal input x = 10; - component x = Multiplier2(); - component y = X(); - component y = Multiplier2(); - component z = Multiplier2(); - - } -template M() { - component h = X(); - component k = Multiplier2(); - test - } -template Multiplier2 () { - template m = M(); - // hello world - signal input a; - signal input b; - signal output c; - component y = X(); - - mintlkrekerjke; - component e = Y(); - component z = Y(); - component h = Y(); - signal output d; - c <== a * b; - } -template Y() { - component y = X(); - component a = X(); - - } - "# - .to_string(); - - let file = FileDB::create(&source, Url::from_file_path(Path::new("/tmp")).unwrap()); - - let syntax_node = SyntaxTreeBuilder::syntax_tree(&source); - - if let Some(program_ast) = AstCircomProgram::cast(syntax_node) { - for template in program_ast.template_list() { - println!("{template:?}"); - } - - let inputs = program_ast.template_list()[0] - .func_body() - .unwrap() - .statement_list() - .unwrap() - .find_children::(); - let signal_name = inputs[0].name().unwrap(); - - let tmp = signal_name.syntax().text_range().start(); - - if let Some(token) = lookup_token_at_postion(&file, &program_ast, file.position(tmp)) { - println!( - "{:#?}", - lookup_node_wrap_token(TokenKind::TemplateDef, &token) - ); - } - } - } - - #[test] - fn url_test() { - let url = Url::from_file_path(Path::new("/hello/abc.tx")); - let binding = url.unwrap(); - let p = binding.path(); - println!("{:?}", Path::new(p).parent()); - } -} +use lsp_types::Location; +use lsp_types::Position; +use lsp_types::Range; +use lsp_types::Url; +use parser::token_kind::TokenKind; +use rowan::ast::AstNode; +use rowan::SyntaxText; + +use syntax::abstract_syntax_tree::AstComponentCall; +use syntax::abstract_syntax_tree::AstInclude; +use syntax::abstract_syntax_tree::AstTemplateDef; +use syntax::abstract_syntax_tree::AstTemplateName; +use syntax::abstract_syntax_tree::{AstCircomProgram, AstComponentDecl}; +use syntax::syntax_node::SyntaxNode; +use syntax::syntax_node::SyntaxToken; + +use crate::database::{FileDB, SemanticData, TokenId}; + +pub fn lookup_node_wrap_token(ast_type: TokenKind, token: &SyntaxToken) -> Option { + let mut p = token.parent(); + while let Some(t) = p { + if t.kind() == ast_type { + return Some(t); + } + p = t.parent(); + } + None +} + +pub fn lookup_token_at_postion( + file: &FileDB, + ast: &AstCircomProgram, + position: Position, +) -> Option { + let off_set = file.off_set(position); + ast.syntax().token_at_offset(off_set).find_map(|token| { + let kind = token.kind(); + + if kind == TokenKind::Identifier { + return Some(token); + } + + if kind == TokenKind::CircomString { + return Some(token); + } + None + }) +} + +pub fn lookup_component(template: &AstTemplateDef, text: SyntaxText) -> Option { + if let Some(statements) = template.statements() { + for component in statements.find_children::() { + if let Some(iden) = component.component_identifier() { + if iden.name().unwrap().syntax().text() == text { + return component.template(); + } + } + } + } + None +} + +pub fn jump_to_lib(file: &FileDB, token: &SyntaxToken) -> Vec { + if let Some(include_lib) = lookup_node_wrap_token(TokenKind::IncludeKw, token) { + if let Some(ast_include) = AstInclude::cast(include_lib) { + if let Some(abs_lib_ans) = ast_include.lib() { + let lib_path = file + .get_path() + .parent() + .unwrap() + .join(abs_lib_ans.value()) + .clone(); + let lib_url = Url::from_file_path(lib_path.clone()).unwrap(); + return vec![Location::new(lib_url, Range::default())]; + } + } + } + + Vec::new() +} + +pub fn lookup_definition( + file: &FileDB, + ast: &AstCircomProgram, + semantic_data: &SemanticData, + token: &SyntaxToken, +) -> Vec { + let template_list = ast.template_list(); + + let mut res = Vec::new(); + + if token.kind() == TokenKind::CircomString { + return jump_to_lib(file, token); + } + + let mut signal_outside = false; + + if let Some(component_call) = lookup_node_wrap_token(TokenKind::ComponentCall, token) { + // find template called. + if let Some(ast_component_call) = AstComponentCall::cast(component_call) { + if let Some(signal) = ast_component_call.signal() { + if signal.syntax().text() == token.text() { + signal_outside = true; + // lookup template of componenet + if let Some(current_template) = + lookup_node_wrap_token(TokenKind::TemplateDef, token) + { + if let Some(ast_template_name) = lookup_component( + &AstTemplateDef::cast(current_template).unwrap(), + ast_component_call.component_name().unwrap().syntax().text(), + ) { + if let Some(other_template) = + ast.get_template_by_name(&ast_template_name) + { + let template_id = other_template.syntax().token_id(); + if let Some(semantic) = + semantic_data.template_data_semantic.get(&template_id) + { + if let Some(tmp) = + semantic.signal.0.get(&signal.syntax().token_id()) + { + res.extend(tmp) + } + } + } + } + } + } + } + } + } + + if !signal_outside { + for template in template_list { + let template_name = template.name().unwrap(); + if template_name.name().unwrap().syntax().text() == token.text() { + let range = file.range(template.syntax()); + res.push(range); + } + + if !template + .syntax() + .text_range() + .contains_range(token.text_range()) + { + continue; + } + + let template_id = template.syntax().token_id(); + + if let Some(data) = semantic_data.lookup_signal(template_id, token) { + res.extend(data); + } + + if let Some(data) = semantic_data.lookup_variable(template_id, token) { + res.extend(data); + } + + if let Some(component_decl) = semantic_data.lookup_component(template_id, token) { + res.extend(component_decl); + } + } + } + + res.into_iter() + .map(|range| Location::new(file.file_path.clone(), range)) + .collect() +} + +#[cfg(test)] +mod tests { + use std::path::Path; + + use lsp_types::Url; + use parser::token_kind::TokenKind; + use rowan::ast::AstNode; + use syntax::{ + abstract_syntax_tree::{AstCircomProgram, AstInputSignalDecl}, + syntax::SyntaxTreeBuilder, + }; + + use crate::{database::FileDB, handler::goto_definition::lookup_node_wrap_token}; + + use super::lookup_token_at_postion; + + #[test] + fn goto_decl_test() { + let source = r#" + pragma circom 2.0.0; + + template X() { + signal x = 10; + signal input x = 10; + component x = Multiplier2(); + component y = X(); + component y = Multiplier2(); + component z = Multiplier2(); + + } +template M() { + component h = X(); + component k = Multiplier2(); + test + } +template Multiplier2 () { + template m = M(); + // hello world + signal input a; + signal input b; + signal output c; + component y = X(); + + mintlkrekerjke; + component e = Y(); + component z = Y(); + component h = Y(); + signal output d; + c <== a * b; + } +template Y() { + component y = X(); + component a = X(); + + } + "# + .to_string(); + + let file = FileDB::create(&source, Url::from_file_path(Path::new("/tmp")).unwrap()); + + let syntax_node = SyntaxTreeBuilder::syntax_tree(&source); + + if let Some(program_ast) = AstCircomProgram::cast(syntax_node) { + for template in program_ast.template_list() { + println!("{template:?}"); + } + + let inputs = program_ast.template_list()[0] + .func_body() + .unwrap() + .statement_list() + .unwrap() + .find_children::(); + let signal_name = inputs[0].name().unwrap(); + + let tmp = signal_name.syntax().text_range().start(); + + if let Some(token) = lookup_token_at_postion(&file, &program_ast, file.position(tmp)) { + println!( + "{:#?}", + lookup_node_wrap_token(TokenKind::TemplateDef, &token) + ); + } + } + } + + #[test] + fn url_test() { + let url = Url::from_file_path(Path::new("/hello/abc.tx")); + let binding = url.unwrap(); + let p = binding.path(); + println!("{:?}", Path::new(p).parent()); + } +} diff --git a/crates/parser/src/grammar/declaration.rs b/crates/parser/src/grammar/declaration.rs index c5dd125..36fd7e0 100644 --- a/crates/parser/src/grammar/declaration.rs +++ b/crates/parser/src/grammar/declaration.rs @@ -1,130 +1,130 @@ -use super::{ - expression::{tuple, tuple_init}, - *, -}; - -// "signal" --> None -// "signal input" --> Some(true) -// "signal output" --> Some(false) -fn signal_header(p: &mut Parser) -> Option { - let mut res = None; - let m = p.open(); - p.expect(SignalKw); - if p.at_any(&[InputKw, OutputKw]) { - if p.at(InputKw) { - res = Some(true); - } else { - res = Some(false); - } - p.advance(); - - if p.at(LCurly) { - p.expect(Identifier); - p.expect(RCurly); - } - } - p.close(m, SignalHeader); - res -} - -/** - * Declaration := "var" (SimpleSymbol, ..., SimpleSymbol) TupleInitialization | - * - * - */ -pub(super) fn var_declaration(p: &mut Parser) { - let m = p.open(); - p.expect(VarKw); - - if p.at(LParen) { - tuple(p); - if p.at(Assign) { - tuple_init(p); - } - } else { - p.expect(Identifier); - if p.at(Assign) { - p.expect(Assign); - expression::expression(p); - } - // list of var - while p.at(Comma) && !p.eof() { - p.expect(Comma); - p.expect(Identifier); - if p.at(Assign) { - p.expect(Assign); - expression::expression(p); - } - } - } - p.close(m, VarDecl); -} - -pub(super) fn signal_declaration(p: &mut Parser) { - if !p.at(SignalKw) { - p.advance_with_error("Signal error"); - return; - } - - let m = p.open(); - let io_signal = signal_header(p); - - if p.at(LParen) { - tuple(p); - if p.at_any(&[Assign, RAssignSignal, RAssignConstraintSignal]) { - tuple_init(p); - } - } else { - p.expect(Identifier); - // list of var - while p.at(Comma) && !p.eof() { - p.skip(); - p.expect(Identifier); - } - } - - if let Some(is_input) = io_signal { - if is_input { - p.close(m, InputSignalDecl); - } else { - p.close(m, OutputSignalDecl); - } - } else { - p.close(m, SignalDecl); - } -} - -pub(super) fn component_declaration(p: &mut Parser) { - let m = p.open(); - p.expect(ComponentKw); - let m_c = p.open(); - p.expect(Identifier); - p.close(m_c, ComponentIdentifier); - - p.expect(Assign); - let m_c = p.open(); - p.expect(Identifier); - p.close(m_c, TemplateName); - p.expect(LParen); - - if p.at(Identifier) { - expression::expression(p); - while !p.at(RParen) && !p.eof() { - p.expect(Comma); - expression::expression(p); - } - } - - p.expect(RParen); - - p.close(m, ComponentDecl); -} - -pub(super) fn declaration(p: &mut Parser) { - match p.current() { - SignalKw => signal_declaration(p), - VarKw => var_declaration(p), - ComponentKw => component_declaration(p), - _ => unreachable!(), - } -} +use super::{ + expression::{tuple, tuple_init}, + *, +}; + +// "signal" --> None +// "signal input" --> Some(true) +// "signal output" --> Some(false) +fn signal_header(p: &mut Parser) -> Option { + let mut res = None; + let m = p.open(); + p.expect(SignalKw); + if p.at_any(&[InputKw, OutputKw]) { + if p.at(InputKw) { + res = Some(true); + } else { + res = Some(false); + } + p.advance(); + + if p.at(LCurly) { + p.expect(Identifier); + p.expect(RCurly); + } + } + p.close(m, SignalHeader); + res +} + +/** + * Declaration := "var" (SimpleSymbol, ..., SimpleSymbol) TupleInitialization | + * + * + */ +pub(super) fn var_declaration(p: &mut Parser) { + let m = p.open(); + p.expect(VarKw); + + if p.at(LParen) { + tuple(p); + if p.at(Assign) { + tuple_init(p); + } + } else { + p.expect(Identifier); + if p.at(Assign) { + p.expect(Assign); + expression::expression(p); + } + // list of var + while p.at(Comma) && !p.eof() { + p.expect(Comma); + p.expect(Identifier); + if p.at(Assign) { + p.expect(Assign); + expression::expression(p); + } + } + } + p.close(m, VarDecl); +} + +pub(super) fn signal_declaration(p: &mut Parser) { + if !p.at(SignalKw) { + p.advance_with_error("Signal error"); + return; + } + + let m = p.open(); + let io_signal = signal_header(p); + + if p.at(LParen) { + tuple(p); + if p.at_any(&[Assign, RAssignSignal, RAssignConstraintSignal]) { + tuple_init(p); + } + } else { + p.expect(Identifier); + // list of var + while p.at(Comma) && !p.eof() { + p.skip(); + p.expect(Identifier); + } + } + + if let Some(is_input) = io_signal { + if is_input { + p.close(m, InputSignalDecl); + } else { + p.close(m, OutputSignalDecl); + } + } else { + p.close(m, SignalDecl); + } +} + +pub(super) fn component_declaration(p: &mut Parser) { + let m = p.open(); + p.expect(ComponentKw); + let m_c = p.open(); + p.expect(Identifier); + p.close(m_c, ComponentIdentifier); + + p.expect(Assign); + let m_c = p.open(); + p.expect(Identifier); + p.close(m_c, TemplateName); + p.expect(LParen); + + if p.at(Identifier) { + expression::expression(p); + while !p.at(RParen) && !p.eof() { + p.expect(Comma); + expression::expression(p); + } + } + + p.expect(RParen); + + p.close(m, ComponentDecl); +} + +pub(super) fn declaration(p: &mut Parser) { + match p.current() { + SignalKw => signal_declaration(p), + VarKw => var_declaration(p), + ComponentKw => component_declaration(p), + _ => unreachable!(), + } +} diff --git a/crates/parser/src/grammar/expression.rs b/crates/parser/src/grammar/expression.rs index 4604da4..1074631 100644 --- a/crates/parser/src/grammar/expression.rs +++ b/crates/parser/src/grammar/expression.rs @@ -1,158 +1,158 @@ -use crate::parser::Marker; - -use super::*; - -pub(super) fn expression(p: &mut Parser) { - let m = p.open(); - circom_expression(p); - p.close(m, Expression); -} - -/** - * grammar: "(Symbol_1, Symbol_2,..., Symbol_n)" - */ -pub(super) fn tuple(p: &mut Parser) { - let m = p.open(); - p.expect(LParen); - p.expect(Identifier); - while p.at(Comma) && !p.eof() { - p.expect(Comma); - p.expect(Identifier); - } - p.expect(RParen); - p.close(m, Tuple); -} - -/** - * grammar: - * "= | <== | <--" expression - */ -pub(super) fn tuple_init(p: &mut Parser) { - let m = p.open(); - p.expect_any(&[Assign, RAssignSignal, RAssignConstraintSignal]); - expression(p); - p.close(m, TupleInit); -} - -fn expression_atom(p: &mut Parser) -> Option { - let m_close: Marker; - match p.current() { - Number => { - let m = p.open(); - p.advance(); - m_close = p.close(m, Number); - Some(m_close) - } - Identifier => { - let m = p.open(); - p.advance(); - m_close = p.close(m, Identifier); - Some(m_close) - } - LParen => { - let m = p.open(); - p.expect(LParen); - expression_rec(p, 0); - p.expect(RParen); - m_close = p.close(m, Tuple); - Some(m_close) - } - _ => { - p.advance_with_error("Invalid Token"); - None - } - } -} - -/** - * return marker which bound the expression - */ -pub fn expression_rec(p: &mut Parser, pb: u16) -> Option { - let parse_able: Option = if let Some(pp) = p.current().prefix() { - let kind = p.current(); - let m = p.open(); - p.advance(); - expression_rec(p, pp); - Some(p.close(m, kind)) - } else { - expression_atom(p) - }; - - parse_able?; - - let mut lhs = parse_able.unwrap(); - - // TODO: function call - if p.at(LParen) { - let m = p.open_before(lhs); - tuple(p); - lhs = p.close(m, Call); - } - - while !p.eof() { - let current_kind = p.current(); - if let Some((lp, rp)) = current_kind.infix() { - if rp <= pb { - return None; - } - - let m = p.open_before(lhs); - p.advance(); - expression_rec(p, lp); - lhs = p.close(m, current_kind); - - continue; - } - if let Some(pp) = current_kind.postfix() { - if pp <= pb { - return None; - } - let m = p.open_before(lhs); - p.advance(); - if matches!(current_kind, LBracket) { - expression_rec(p, 0); - p.expect(RBracket); - } else { - p.expect(Identifier); - } - lhs = if matches!(current_kind, Dot) { - p.close(m, ComponentCall) - } else { - p.close(m, ArrayQuery) - }; - - continue; - } - break; - } - Some(lhs) -} - -/** - * circom_expression = expr ? expr: expr | - * expr - */ -fn circom_expression(p: &mut Parser) { - if let Some(mut lhs) = expression_rec(p, 0) { - let current_kind = p.current(); - if matches!(current_kind, MarkQuestion) { - let m = p.open_before(lhs); - lhs = p.close(m, Condition); - - let m = p.open_before(lhs); - p.advance(); - - let first_expression = p.open(); - expression_rec(p, 0); - p.close(first_expression, Expression); - - p.expect(Colon); - - let last_expression = p.open(); - expression_rec(p, 0); - p.close(last_expression, Expression); - - p.close(m, TenaryConditional); - } - } -} +use crate::parser::Marker; + +use super::*; + +pub(super) fn expression(p: &mut Parser) { + let m = p.open(); + circom_expression(p); + p.close(m, Expression); +} + +/** + * grammar: "(Symbol_1, Symbol_2,..., Symbol_n)" + */ +pub(super) fn tuple(p: &mut Parser) { + let m = p.open(); + p.expect(LParen); + p.expect(Identifier); + while p.at(Comma) && !p.eof() { + p.expect(Comma); + p.expect(Identifier); + } + p.expect(RParen); + p.close(m, Tuple); +} + +/** + * grammar: + * "= | <== | <--" expression + */ +pub(super) fn tuple_init(p: &mut Parser) { + let m = p.open(); + p.expect_any(&[Assign, RAssignSignal, RAssignConstraintSignal]); + expression(p); + p.close(m, TupleInit); +} + +fn expression_atom(p: &mut Parser) -> Option { + let m_close: Marker; + match p.current() { + Number => { + let m = p.open(); + p.advance(); + m_close = p.close(m, Number); + Some(m_close) + } + Identifier => { + let m = p.open(); + p.advance(); + m_close = p.close(m, Identifier); + Some(m_close) + } + LParen => { + let m = p.open(); + p.expect(LParen); + expression_rec(p, 0); + p.expect(RParen); + m_close = p.close(m, Tuple); + Some(m_close) + } + _ => { + p.advance_with_error("Invalid Token"); + None + } + } +} + +/** + * return marker which bound the expression + */ +pub fn expression_rec(p: &mut Parser, pb: u16) -> Option { + let parse_able: Option = if let Some(pp) = p.current().prefix() { + let kind = p.current(); + let m = p.open(); + p.advance(); + expression_rec(p, pp); + Some(p.close(m, kind)) + } else { + expression_atom(p) + }; + + parse_able?; + + let mut lhs = parse_able.unwrap(); + + // TODO: function call + if p.at(LParen) { + let m = p.open_before(lhs); + tuple(p); + lhs = p.close(m, Call); + } + + while !p.eof() { + let current_kind = p.current(); + if let Some((lp, rp)) = current_kind.infix() { + if rp <= pb { + return None; + } + + let m = p.open_before(lhs); + p.advance(); + expression_rec(p, lp); + lhs = p.close(m, current_kind); + + continue; + } + if let Some(pp) = current_kind.postfix() { + if pp <= pb { + return None; + } + let m = p.open_before(lhs); + p.advance(); + if matches!(current_kind, LBracket) { + expression_rec(p, 0); + p.expect(RBracket); + } else { + p.expect(Identifier); + } + lhs = if matches!(current_kind, Dot) { + p.close(m, ComponentCall) + } else { + p.close(m, ArrayQuery) + }; + + continue; + } + break; + } + Some(lhs) +} + +/** + * circom_expression = expr ? expr: expr | + * expr + */ +fn circom_expression(p: &mut Parser) { + if let Some(mut lhs) = expression_rec(p, 0) { + let current_kind = p.current(); + if matches!(current_kind, MarkQuestion) { + let m = p.open_before(lhs); + lhs = p.close(m, Condition); + + let m = p.open_before(lhs); + p.advance(); + + let first_expression = p.open(); + expression_rec(p, 0); + p.close(first_expression, Expression); + + p.expect(Colon); + + let last_expression = p.open(); + expression_rec(p, 0); + p.close(last_expression, Expression); + + p.close(m, TenaryConditional); + } + } +} diff --git a/crates/parser/src/grammar/statement.rs b/crates/parser/src/grammar/statement.rs index 84ca0a6..2828f3c 100644 --- a/crates/parser/src/grammar/statement.rs +++ b/crates/parser/src/grammar/statement.rs @@ -1,184 +1,184 @@ -use super::{block::block, expression::expression, *}; - -pub(super) fn statement(p: &mut Parser) { - let m = p.open(); - match p.current() { - IfKw => if_statement(p), - _ => statement_no_condition(p), - } - p.close(m, Statement); -} - -/* -if (expr) - -else - -*/ -fn if_statement(p: &mut Parser) { - let m = p.open(); - p.expect(IfKw); - p.expect(LParen); - expression::expression(p); - p.expect(RParen); - statement(p); - if p.at(ElseKw) { - p.expect(ElseKw); - statement(p); - } - p.close(m, IfKw); -} - -/** - * no if condition here. - * for/while/return/assert... - */ -fn statement_no_condition(p: &mut Parser) { - match p.current() { - ForKw => for_statement(p), - WhileKw => while_statement(p), - ReturnKw => { - return_statement(p); - p.expect(Semicolon); - } - LCurly => block(p), - LogKw => { - log_statement(p); - p.expect(Semicolon); - } - AssertKw => { - assert_statement(p); - p.expect(Semicolon); - } - _ => { - assignment_statement(p); - p.expect(Semicolon); - } - } -} - -/* -for (/; ; ) - -*/ -fn for_statement(p: &mut Parser) { - let m = p.open(); - p.expect(ForKw); - p.expect(LParen); - if p.current().is_declaration_kw() { - declaration::declaration(p); - } else { - assignment_statement(p); - } - p.expect(Semicolon); - expression::expression(p); - p.expect(Semicolon); - - assignment_statement(p); - p.expect(RParen); - - statement_no_condition(p); - p.close(m, ForLoop); -} - -/* -while () - -*/ -fn while_statement(p: &mut Parser) { - p.expect(WhileKw); - p.expect(LParen); - expression(p); - p.expect(RParen); - statement(p); -} - -/* -assert() -*/ -fn assert_statement(p: &mut Parser) { - let m = p.open(); - p.expect(AssertKw); - p.expect(LParen); - expression(p); - p.expect(RParen); - p.close(m, AssertKw); -} - -/* -log() -*/ -fn log_statement(p: &mut Parser) { - let m = p.open(); - p.expect(LogKw); - p.expect(LParen); - while !p.eof() { - if p.at(RParen) { - break; - } - match p.current() { - CircomString => p.advance(), - _ => expression(p), - } - if !p.at(Comma) { - break; - } else { - p.advance(); - } - } - p.expect(RParen); - p.close(m, LogKw); -} - -/* -return -*/ -fn return_statement(p: &mut Parser) { - let m = p.open(); - p.expect(ReturnKw); - expression(p); - p.close(m, ReturnKw); -} - -/* - -*/ -fn assignment_statement(p: &mut Parser) { - let m = p.open(); - - if p.at(Identifier) { - let m_id = p.open(); - let m_name = p.open(); - p.expect(Identifier); - p.close(m_name, ComponentIdentifier); - if p.at(LBracket) { - p.expect(LBracket); - expression(p); - p.expect(RBracket); - } - if p.at(Dot) { - p.expect(Dot); - p.expect(Identifier); - p.close(m_id, ComponentCall); - } else { - p.close(m_id, Expression); - } - } else { - expression(p); - } - - if p.at_any(&[ - Assign, - RAssignSignal, - RAssignConstraintSignal, - LAssignContraintSignal, - LAssignSignal, - EqualSignal, - ]) { - p.advance(); - expression(p); - p.close(m, AssignStatement); - } else { - p.close(m, Error); - } -} +use super::{block::block, expression::expression, *}; + +pub(super) fn statement(p: &mut Parser) { + let m = p.open(); + match p.current() { + IfKw => if_statement(p), + _ => statement_no_condition(p), + } + p.close(m, Statement); +} + +/* +if (expr) + +else + +*/ +fn if_statement(p: &mut Parser) { + let m = p.open(); + p.expect(IfKw); + p.expect(LParen); + expression::expression(p); + p.expect(RParen); + statement(p); + if p.at(ElseKw) { + p.expect(ElseKw); + statement(p); + } + p.close(m, IfKw); +} + +/** + * no if condition here. + * for/while/return/assert... + */ +fn statement_no_condition(p: &mut Parser) { + match p.current() { + ForKw => for_statement(p), + WhileKw => while_statement(p), + ReturnKw => { + return_statement(p); + p.expect(Semicolon); + } + LCurly => block(p), + LogKw => { + log_statement(p); + p.expect(Semicolon); + } + AssertKw => { + assert_statement(p); + p.expect(Semicolon); + } + _ => { + assignment_statement(p); + p.expect(Semicolon); + } + } +} + +/* +for (/; ; ) + +*/ +fn for_statement(p: &mut Parser) { + let m = p.open(); + p.expect(ForKw); + p.expect(LParen); + if p.current().is_declaration_kw() { + declaration::declaration(p); + } else { + assignment_statement(p); + } + p.expect(Semicolon); + expression::expression(p); + p.expect(Semicolon); + + assignment_statement(p); + p.expect(RParen); + + statement_no_condition(p); + p.close(m, ForLoop); +} + +/* +while () + +*/ +fn while_statement(p: &mut Parser) { + p.expect(WhileKw); + p.expect(LParen); + expression(p); + p.expect(RParen); + statement(p); +} + +/* +assert() +*/ +fn assert_statement(p: &mut Parser) { + let m = p.open(); + p.expect(AssertKw); + p.expect(LParen); + expression(p); + p.expect(RParen); + p.close(m, AssertKw); +} + +/* +log() +*/ +fn log_statement(p: &mut Parser) { + let m = p.open(); + p.expect(LogKw); + p.expect(LParen); + while !p.eof() { + if p.at(RParen) { + break; + } + match p.current() { + CircomString => p.advance(), + _ => expression(p), + } + if !p.at(Comma) { + break; + } else { + p.advance(); + } + } + p.expect(RParen); + p.close(m, LogKw); +} + +/* +return +*/ +fn return_statement(p: &mut Parser) { + let m = p.open(); + p.expect(ReturnKw); + expression(p); + p.close(m, ReturnKw); +} + +/* + +*/ +fn assignment_statement(p: &mut Parser) { + let m = p.open(); + + if p.at(Identifier) { + let m_id = p.open(); + let m_name = p.open(); + p.expect(Identifier); + p.close(m_name, ComponentIdentifier); + if p.at(LBracket) { + p.expect(LBracket); + expression(p); + p.expect(RBracket); + } + if p.at(Dot) { + p.expect(Dot); + p.expect(Identifier); + p.close(m_id, ComponentCall); + } else { + p.close(m_id, Expression); + } + } else { + expression(p); + } + + if p.at_any(&[ + Assign, + RAssignSignal, + RAssignConstraintSignal, + LAssignContraintSignal, + LAssignSignal, + EqualSignal, + ]) { + p.advance(); + expression(p); + p.close(m, AssignStatement); + } else { + p.close(m, Error); + } +} diff --git a/crates/parser/src/grammar/template.rs b/crates/parser/src/grammar/template.rs index a502365..9cfa7cb 100644 --- a/crates/parser/src/grammar/template.rs +++ b/crates/parser/src/grammar/template.rs @@ -1,25 +1,25 @@ -use crate::grammar::*; -/** - * template Identifier() {content} - * template Identifier( param_1, ... , param_n ) { content } - */ -pub fn template(p: &mut Parser) { - // assert!(p.at(TemplateKw)); - let m = p.open(); - - p.expect(TemplateKw); - - let name_marker = p.open(); - p.expect(Identifier); - p.close(name_marker, TemplateName); - - p.expect(LParen); - let arg_marker = p.open(); - list_identity::parse(p); - p.close(arg_marker, ParameterList); - p.expect(RParen); - - block::block(p); - - p.close(m, TemplateDef); -} +use crate::grammar::*; +/** + * template Identifier() {content} + * template Identifier( param_1, ... , param_n ) { content } + */ +pub fn template(p: &mut Parser) { + // assert!(p.at(TemplateKw)); + let m = p.open(); + + p.expect(TemplateKw); + + let name_marker = p.open(); + p.expect(Identifier); + p.close(name_marker, TemplateName); + + p.expect(LParen); + let arg_marker = p.open(); + list_identity::parse(p); + p.close(arg_marker, ParameterList); + p.expect(RParen); + + block::block(p); + + p.close(m, TemplateDef); +} diff --git a/crates/parser/src/snapshots/parser__input__tests__test_operators.snap b/crates/parser/src/snapshots/parser__input__tests__test_operators.snap index 1366b66..a7a3155 100644 --- a/crates/parser/src/snapshots/parser__input__tests__test_operators.snap +++ b/crates/parser/src/snapshots/parser__input__tests__test_operators.snap @@ -1,391 +1,391 @@ ---- -source: crates/parser/src/input.rs -expression: input ---- -kind: - - EndLine - - WhiteSpace - - LParen - - LCurly - - LBracket - - RBracket - - RCurly - - RParen - - EndLine - - WhiteSpace - - Semicolon - - Dot - - Comma - - Colon - - EndLine - - WhiteSpace - - BoolAnd - - WhiteSpace - - BitAnd - - EndLine - - WhiteSpace - - BoolOr - - WhiteSpace - - BitOr - - EndLine - - WhiteSpace - - NotEqual - - WhiteSpace - - Not - - EndLine - - WhiteSpace - - EqualSignal - - WhiteSpace - - Equal - - WhiteSpace - - Assign - - EndLine - - WhiteSpace - - LAssignSignal - - WhiteSpace - - LAssignContraintSignal - - EndLine - - WhiteSpace - - RAssignSignal - - WhiteSpace - - RAssignConstraintSignal - - EndLine - - WhiteSpace - - LessThanAndEqual - - WhiteSpace - - LessThan - - EndLine - - WhiteSpace - - GreaterThanAndEqual - - WhiteSpace - - GreaterThan - - EndLine - - WhiteSpace - - UnitInc - - WhiteSpace - - AddAssign - - WhiteSpace - - Add - - EndLine - - WhiteSpace - - UnitDec - - WhiteSpace - - SubAssign - - WhiteSpace - - Sub - - EndLine - - WhiteSpace - - PowerAssign - - WhiteSpace - - Power - - EndLine - - WhiteSpace - - Mul - - WhiteSpace - - MulAssign - - EndLine - - WhiteSpace - - Div - - WhiteSpace - - DivAssign - - EndLine - - WhiteSpace - - IntDiv - - WhiteSpace - - IntDivAssign - - EndLine - - WhiteSpace - - Mod - - WhiteSpace - - ModAssign - - EndLine - - WhiteSpace - - BitXor - - WhiteSpace - - BitXorAssign - - EndLine - - WhiteSpace - - BitNot - - WhiteSpace - - BitNotAssign - - EndLine - - WhiteSpace - - ShiftR - - WhiteSpace - - ShiftRAssign - - EndLine - - WhiteSpace - - ShiftL - - WhiteSpace - - ShiftLAssign - - EndLine - - WhiteSpace - - BitAnd - - WhiteSpace - - BitAndAssign - - EndLine - - WhiteSpace - - BitOr - - WhiteSpace - - BitOrAssign - - EndLine - - WhiteSpace - - RCurly -source: "\n ({[]})\n ;.,:\n && &\n || |\n != !\n === == =\n --> ==>\n <-- <==\n <= <\n >= >\n ++ += +\n -- -= -\n **= **\n * *=\n / /=\n \\ \\=\n % %=\n ^ ^=\n ~ ~=\n >> >>=\n << <<=\n & &=\n | |=\n }" -position: - - start: 0 - end: 1 - - start: 1 - end: 9 - - start: 9 - end: 10 - - start: 10 - end: 11 - - start: 11 - end: 12 - - start: 12 - end: 13 - - start: 13 - end: 14 - - start: 14 - end: 15 - - start: 15 - end: 16 - - start: 16 - end: 24 - - start: 24 - end: 25 - - start: 25 - end: 26 - - start: 26 - end: 27 - - start: 27 - end: 28 - - start: 28 - end: 29 - - start: 29 - end: 37 - - start: 37 - end: 39 - - start: 39 - end: 40 - - start: 40 - end: 41 - - start: 41 - end: 42 - - start: 42 - end: 50 - - start: 50 - end: 52 - - start: 52 - end: 53 - - start: 53 - end: 54 - - start: 54 - end: 55 - - start: 55 - end: 63 - - start: 63 - end: 65 - - start: 65 - end: 66 - - start: 66 - end: 67 - - start: 67 - end: 68 - - start: 68 - end: 76 - - start: 76 - end: 79 - - start: 79 - end: 80 - - start: 80 - end: 82 - - start: 82 - end: 83 - - start: 83 - end: 84 - - start: 84 - end: 85 - - start: 85 - end: 93 - - start: 93 - end: 96 - - start: 96 - end: 97 - - start: 97 - end: 100 - - start: 100 - end: 101 - - start: 101 - end: 109 - - start: 109 - end: 112 - - start: 112 - end: 113 - - start: 113 - end: 116 - - start: 116 - end: 117 - - start: 117 - end: 125 - - start: 125 - end: 127 - - start: 127 - end: 128 - - start: 128 - end: 129 - - start: 129 - end: 130 - - start: 130 - end: 138 - - start: 138 - end: 140 - - start: 140 - end: 141 - - start: 141 - end: 142 - - start: 142 - end: 143 - - start: 143 - end: 151 - - start: 151 - end: 153 - - start: 153 - end: 154 - - start: 154 - end: 156 - - start: 156 - end: 157 - - start: 157 - end: 158 - - start: 158 - end: 159 - - start: 159 - end: 167 - - start: 167 - end: 169 - - start: 169 - end: 170 - - start: 170 - end: 172 - - start: 172 - end: 173 - - start: 173 - end: 174 - - start: 174 - end: 175 - - start: 175 - end: 183 - - start: 183 - end: 186 - - start: 186 - end: 187 - - start: 187 - end: 189 - - start: 189 - end: 190 - - start: 190 - end: 198 - - start: 198 - end: 199 - - start: 199 - end: 200 - - start: 200 - end: 202 - - start: 202 - end: 203 - - start: 203 - end: 211 - - start: 211 - end: 212 - - start: 212 - end: 213 - - start: 213 - end: 215 - - start: 215 - end: 216 - - start: 216 - end: 224 - - start: 224 - end: 225 - - start: 225 - end: 226 - - start: 226 - end: 228 - - start: 228 - end: 229 - - start: 229 - end: 237 - - start: 237 - end: 238 - - start: 238 - end: 239 - - start: 239 - end: 241 - - start: 241 - end: 242 - - start: 242 - end: 250 - - start: 250 - end: 251 - - start: 251 - end: 252 - - start: 252 - end: 254 - - start: 254 - end: 255 - - start: 255 - end: 263 - - start: 263 - end: 264 - - start: 264 - end: 265 - - start: 265 - end: 267 - - start: 267 - end: 268 - - start: 268 - end: 276 - - start: 276 - end: 278 - - start: 278 - end: 279 - - start: 279 - end: 282 - - start: 282 - end: 283 - - start: 283 - end: 291 - - start: 291 - end: 293 - - start: 293 - end: 294 - - start: 294 - end: 297 - - start: 297 - end: 298 - - start: 298 - end: 306 - - start: 306 - end: 307 - - start: 307 - end: 308 - - start: 308 - end: 310 - - start: 310 - end: 311 - - start: 311 - end: 319 - - start: 319 - end: 320 - - start: 320 - end: 321 - - start: 321 - end: 323 - - start: 323 - end: 324 - - start: 324 - end: 328 - - start: 328 - end: 329 +--- +source: crates/parser/src/input.rs +expression: input +--- +kind: + - EndLine + - WhiteSpace + - LParen + - LCurly + - LBracket + - RBracket + - RCurly + - RParen + - EndLine + - WhiteSpace + - Semicolon + - Dot + - Comma + - Colon + - EndLine + - WhiteSpace + - BoolAnd + - WhiteSpace + - BitAnd + - EndLine + - WhiteSpace + - BoolOr + - WhiteSpace + - BitOr + - EndLine + - WhiteSpace + - NotEqual + - WhiteSpace + - Not + - EndLine + - WhiteSpace + - EqualSignal + - WhiteSpace + - Equal + - WhiteSpace + - Assign + - EndLine + - WhiteSpace + - LAssignSignal + - WhiteSpace + - LAssignContraintSignal + - EndLine + - WhiteSpace + - RAssignSignal + - WhiteSpace + - RAssignConstraintSignal + - EndLine + - WhiteSpace + - LessThanAndEqual + - WhiteSpace + - LessThan + - EndLine + - WhiteSpace + - GreaterThanAndEqual + - WhiteSpace + - GreaterThan + - EndLine + - WhiteSpace + - UnitInc + - WhiteSpace + - AddAssign + - WhiteSpace + - Add + - EndLine + - WhiteSpace + - UnitDec + - WhiteSpace + - SubAssign + - WhiteSpace + - Sub + - EndLine + - WhiteSpace + - PowerAssign + - WhiteSpace + - Power + - EndLine + - WhiteSpace + - Mul + - WhiteSpace + - MulAssign + - EndLine + - WhiteSpace + - Div + - WhiteSpace + - DivAssign + - EndLine + - WhiteSpace + - IntDiv + - WhiteSpace + - IntDivAssign + - EndLine + - WhiteSpace + - Mod + - WhiteSpace + - ModAssign + - EndLine + - WhiteSpace + - BitXor + - WhiteSpace + - BitXorAssign + - EndLine + - WhiteSpace + - BitNot + - WhiteSpace + - BitNotAssign + - EndLine + - WhiteSpace + - ShiftR + - WhiteSpace + - ShiftRAssign + - EndLine + - WhiteSpace + - ShiftL + - WhiteSpace + - ShiftLAssign + - EndLine + - WhiteSpace + - BitAnd + - WhiteSpace + - BitAndAssign + - EndLine + - WhiteSpace + - BitOr + - WhiteSpace + - BitOrAssign + - EndLine + - WhiteSpace + - RCurly +source: "\n ({[]})\n ;.,:\n && &\n || |\n != !\n === == =\n --> ==>\n <-- <==\n <= <\n >= >\n ++ += +\n -- -= -\n **= **\n * *=\n / /=\n \\ \\=\n % %=\n ^ ^=\n ~ ~=\n >> >>=\n << <<=\n & &=\n | |=\n }" +position: + - start: 0 + end: 1 + - start: 1 + end: 9 + - start: 9 + end: 10 + - start: 10 + end: 11 + - start: 11 + end: 12 + - start: 12 + end: 13 + - start: 13 + end: 14 + - start: 14 + end: 15 + - start: 15 + end: 16 + - start: 16 + end: 24 + - start: 24 + end: 25 + - start: 25 + end: 26 + - start: 26 + end: 27 + - start: 27 + end: 28 + - start: 28 + end: 29 + - start: 29 + end: 37 + - start: 37 + end: 39 + - start: 39 + end: 40 + - start: 40 + end: 41 + - start: 41 + end: 42 + - start: 42 + end: 50 + - start: 50 + end: 52 + - start: 52 + end: 53 + - start: 53 + end: 54 + - start: 54 + end: 55 + - start: 55 + end: 63 + - start: 63 + end: 65 + - start: 65 + end: 66 + - start: 66 + end: 67 + - start: 67 + end: 68 + - start: 68 + end: 76 + - start: 76 + end: 79 + - start: 79 + end: 80 + - start: 80 + end: 82 + - start: 82 + end: 83 + - start: 83 + end: 84 + - start: 84 + end: 85 + - start: 85 + end: 93 + - start: 93 + end: 96 + - start: 96 + end: 97 + - start: 97 + end: 100 + - start: 100 + end: 101 + - start: 101 + end: 109 + - start: 109 + end: 112 + - start: 112 + end: 113 + - start: 113 + end: 116 + - start: 116 + end: 117 + - start: 117 + end: 125 + - start: 125 + end: 127 + - start: 127 + end: 128 + - start: 128 + end: 129 + - start: 129 + end: 130 + - start: 130 + end: 138 + - start: 138 + end: 140 + - start: 140 + end: 141 + - start: 141 + end: 142 + - start: 142 + end: 143 + - start: 143 + end: 151 + - start: 151 + end: 153 + - start: 153 + end: 154 + - start: 154 + end: 156 + - start: 156 + end: 157 + - start: 157 + end: 158 + - start: 158 + end: 159 + - start: 159 + end: 167 + - start: 167 + end: 169 + - start: 169 + end: 170 + - start: 170 + end: 172 + - start: 172 + end: 173 + - start: 173 + end: 174 + - start: 174 + end: 175 + - start: 175 + end: 183 + - start: 183 + end: 186 + - start: 186 + end: 187 + - start: 187 + end: 189 + - start: 189 + end: 190 + - start: 190 + end: 198 + - start: 198 + end: 199 + - start: 199 + end: 200 + - start: 200 + end: 202 + - start: 202 + end: 203 + - start: 203 + end: 211 + - start: 211 + end: 212 + - start: 212 + end: 213 + - start: 213 + end: 215 + - start: 215 + end: 216 + - start: 216 + end: 224 + - start: 224 + end: 225 + - start: 225 + end: 226 + - start: 226 + end: 228 + - start: 228 + end: 229 + - start: 229 + end: 237 + - start: 237 + end: 238 + - start: 238 + end: 239 + - start: 239 + end: 241 + - start: 241 + end: 242 + - start: 242 + end: 250 + - start: 250 + end: 251 + - start: 251 + end: 252 + - start: 252 + end: 254 + - start: 254 + end: 255 + - start: 255 + end: 263 + - start: 263 + end: 264 + - start: 264 + end: 265 + - start: 265 + end: 267 + - start: 267 + end: 268 + - start: 268 + end: 276 + - start: 276 + end: 278 + - start: 278 + end: 279 + - start: 279 + end: 282 + - start: 282 + end: 283 + - start: 283 + end: 291 + - start: 291 + end: 293 + - start: 293 + end: 294 + - start: 294 + end: 297 + - start: 297 + end: 298 + - start: 298 + end: 306 + - start: 306 + end: 307 + - start: 307 + end: 308 + - start: 308 + end: 310 + - start: 310 + end: 311 + - start: 311 + end: 319 + - start: 319 + end: 320 + - start: 320 + end: 321 + - start: 321 + end: 323 + - start: 323 + end: 324 + - start: 324 + end: 328 + - start: 328 + end: 329 diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 21d3625..98ef766 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -1,359 +1,359 @@ -use logos::Logos; -use serde::Serialize; - -#[derive(Logos, Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord, Hash, Serialize)] -#[allow(non_camel_case_types)] -#[repr(u16)] -pub enum TokenKind { - // Error - #[error] - Error = 0, - // Comments - #[regex(r"//[^\n]*")] - CommentLine, - #[token("/*")] - CommentBlockOpen, - #[token("*/")] - CommentBlockClose, - // Trivial - #[regex("[ \t]+")] - WhiteSpace, - #[regex("[\n]")] - EndLine, - // Circom - #[token("pragma")] - Pragma, - #[token("circom")] - Circom, - #[regex("2.[0-9].[0-9]")] - Version, - // Literals - #[regex("[0-9]+")] - Number, - #[regex("[$_]*[a-zA-Z][a-zA-Z0-9_$]*")] - Identifier, - #[regex(r#""[^"]*""#)] - CircomString, - // Brackets - #[token("(")] - LParen, - #[token(")")] - RParen, - #[token("{")] - LCurly, - #[token("}")] - RCurly, - #[token("[")] - LBracket, - #[token("]")] - RBracket, - // Punctuation - #[token(";")] - Semicolon, - #[token(",")] - Comma, - #[token(".")] - Dot, - // Boolean operators - #[token("&&")] - BoolAnd, - #[token("||")] - BoolOr, - #[token("!")] - Not, - // Relational operators - #[token("==")] - Equal, - #[token("!=")] - NotEqual, - #[token("<")] - LessThan, - #[token(">")] - GreaterThan, - #[token("<=")] - LessThanAndEqual, - #[token(">=")] - GreaterThanAndEqual, - // Arithmetic operators - #[token("+")] - Add, - #[token("-")] - Sub, - #[token("*")] - Mul, - #[token("**")] - Power, - #[token("/")] - Div, - #[token("\\")] - IntDiv, - #[token("%")] - Mod, - // Combined arithmetic assignment - #[token("+=")] - AddAssign, - #[token("-=")] - SubAssign, - #[token("*=")] - MulAssign, - #[token("**=")] - PowerAssign, - #[token("/=")] - DivAssign, - #[token(r"\=")] - IntDivAssign, - #[token("%=")] - ModAssign, - #[token("++")] - UnitInc, - #[token("--")] - UnitDec, - // Bitwise operators - #[token("&")] - BitAnd, - #[token("|")] - BitOr, - #[token("~")] - BitNot, - #[token("^")] - BitXor, - #[token(">>")] - ShiftR, - #[token("<<")] - ShiftL, - // Combined bitwise assignments - #[token("&=")] - BitAndAssign, - #[token("|=")] - BitOrAssign, - #[token("~=")] - BitNotAssign, - #[token("^=")] - BitXorAssign, - #[token(">>=")] - ShiftRAssign, - #[token("<<=")] - ShiftLAssign, - // Assign - #[token("=")] - Assign, - #[token("===")] - EqualSignal, - #[token("-->")] - LAssignSignal, - #[token("==>")] - LAssignContraintSignal, - #[token("<--")] - RAssignSignal, - #[token("<==")] - RAssignConstraintSignal, - // Conditional expressions - #[token("?")] - MarkQuestion, - #[token(":")] - Colon, - // Keywords - #[token("template")] - TemplateKw, - #[token("function")] - FunctionKw, - #[token("component")] - ComponentKw, - #[token("main")] - MainKw, - #[token("public")] - PublicKw, - #[token("signal")] - SignalKw, - #[token("var")] - VarKw, - #[token("include")] - IncludeKw, - #[token("input")] - InputKw, - #[token("output")] - OutputKw, - #[token("log")] - LogKw, - // Statement keywords - #[token("if")] - IfKw, - #[token("else")] - ElseKw, - #[token("for")] - ForKw, - #[token("while")] - WhileKw, - #[token("return")] - ReturnKw, - #[token("assert")] - AssertKw, - // Complex token kind - ForLoop, - AssignStatement, - CircomProgram, - SignalOfComponent, - SignalHeader, - Block, - Tuple, - TupleInit, - Call, - TenaryConditional, - Condition, - Expression, - FunctionDef, - Statement, - StatementList, - ComponentDecl, - TemplateDef, - TemplateName, - FunctionName, - ParameterList, - SignalDecl, - VarDecl, - InputSignalDecl, - OutputSignalDecl, - ComponentCall, - ComponentIdentifier, - SignalIdentifier, - ArrayQuery, - ParserError, - BlockComment, - EOF, - ROOT, - __LAST, -} - -impl From for TokenKind { - #[inline] - fn from(d: u16) -> TokenKind { - assert!(d <= (TokenKind::__LAST as u16)); - unsafe { std::mem::transmute::(d) } - } -} - -impl From for TokenKind { - fn from(value: rowan::SyntaxKind) -> Self { - match value { - rowan::SyntaxKind(id) => TokenKind::from(id), - } - } -} - -impl From for u16 { - #[inline] - fn from(k: TokenKind) -> u16 { - k as u16 - } -} - -impl From for rowan::SyntaxKind { - fn from(kind: TokenKind) -> Self { - Self(kind as u16) - } -} - -impl TokenKind { - // a + 10 --> a and 10 are literals - pub fn is_literal(self) -> bool { - matches!(self, Self::Number | Self::Identifier) - } - - // these tokens have the lowest priority - // infix_operator - // eg: a + b --> + is an infix token - pub fn infix(self) -> Option<(u16, u16)> { - match self { - // arithmetic operators - Self::Power => Some((99, 100)), - Self::Mul | Self::Div | Self::IntDiv | Self::Mod => Some((94, 95)), - Self::Add | Self::Sub => Some((89, 90)), - - // shift bitwise operators - Self::ShiftL | Self::ShiftR => Some((84, 85)), - - // relational operators - Self::LessThan - | Self::GreaterThan - | Self::LessThanAndEqual - | Self::GreaterThanAndEqual => Some((79, 80)), - Self::Equal - | Self::NotEqual => Some((74, 75)), - - // other bitwise operators - Self::BitAnd => Some((69, 70)), - Self::BitXor => Some((64, 65)), // exclusive or - Self::BitOr => Some((59, 60)), - - // boolean operators - Self::BoolAnd => Some((54, 55)), - Self::BoolOr => Some((49, 50)), - - // TODO: how about conditional operation ( ? : ) - // associativity: right to left [ a ? b : c --> ??? ] - - // associativity: right to left [ a = b = c --> a = (b = c) ] - // assignment operators - Self::Assign - // bitwise asignment operators - | Self::BitOrAssign - | Self::BitXorAssign - | Self::BitAndAssign - | Self::ShiftLAssign - | Self::ShiftRAssign - // arithmetic asignament operators - | Self::AddAssign - | Self::SubAssign - | Self::MulAssign - | Self::DivAssign - | Self::IntDivAssign - | Self::ModAssign - | Self::PowerAssign => Some((44, 45)), - - // TODO: how about comma (expression separator) - Self::Comma => Some((39, 40)), - - // not an infix operator - _ => None, - } - } - - // priority: post > pre > in - // associativity: right to left [ --!a --> --(!a) ] - // prefix_operator - // eg: -10, !a, ++a, --a - pub fn prefix(self) -> Option { - match self { - Self::UnitDec | Self::UnitInc - | Self::Sub | Self::Add - | Self::Not | Self::BitNot => Some(200), - - _ => None, - } - } - - // these tokens have the highest priority - // postfix_operator - // eg: a[10], b++, c.att1 - pub fn postfix(self) -> Option { - match self { - Self::LParen // function call - | Self::LBracket // array subscript - | Self::Dot // attribute access - | Self::UnitDec | Self::UnitInc => Some(300), - - _ => None, - } - } - - pub fn is_declaration_kw(self) -> bool { - matches!(self, Self::VarKw | Self::ComponentKw | Self::SignalKw) - } - - pub fn is_trivial(self) -> bool { - matches!( - self, - Self::WhiteSpace | Self::EndLine | Self::CommentLine | Self::BlockComment | Self::Error - ) - } -} +use logos::Logos; +use serde::Serialize; + +#[derive(Logos, Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord, Hash, Serialize)] +#[allow(non_camel_case_types)] +#[repr(u16)] +pub enum TokenKind { + // Error + #[error] + Error = 0, + // Comments + #[regex(r"//[^\n]*")] + CommentLine, + #[token("/*")] + CommentBlockOpen, + #[token("*/")] + CommentBlockClose, + // Trivial + #[regex("[ \t]+")] + WhiteSpace, + #[regex("[\n]")] + EndLine, + // Circom + #[token("pragma")] + Pragma, + #[token("circom")] + Circom, + #[regex("2.[0-9].[0-9]")] + Version, + // Literals + #[regex("[0-9]+")] + Number, + #[regex("[$_]*[a-zA-Z][a-zA-Z0-9_$]*")] + Identifier, + #[regex(r#""[^"]*""#)] + CircomString, + // Brackets + #[token("(")] + LParen, + #[token(")")] + RParen, + #[token("{")] + LCurly, + #[token("}")] + RCurly, + #[token("[")] + LBracket, + #[token("]")] + RBracket, + // Punctuation + #[token(";")] + Semicolon, + #[token(",")] + Comma, + #[token(".")] + Dot, + // Boolean operators + #[token("&&")] + BoolAnd, + #[token("||")] + BoolOr, + #[token("!")] + Not, + // Relational operators + #[token("==")] + Equal, + #[token("!=")] + NotEqual, + #[token("<")] + LessThan, + #[token(">")] + GreaterThan, + #[token("<=")] + LessThanAndEqual, + #[token(">=")] + GreaterThanAndEqual, + // Arithmetic operators + #[token("+")] + Add, + #[token("-")] + Sub, + #[token("*")] + Mul, + #[token("**")] + Power, + #[token("/")] + Div, + #[token("\\")] + IntDiv, + #[token("%")] + Mod, + // Combined arithmetic assignment + #[token("+=")] + AddAssign, + #[token("-=")] + SubAssign, + #[token("*=")] + MulAssign, + #[token("**=")] + PowerAssign, + #[token("/=")] + DivAssign, + #[token(r"\=")] + IntDivAssign, + #[token("%=")] + ModAssign, + #[token("++")] + UnitInc, + #[token("--")] + UnitDec, + // Bitwise operators + #[token("&")] + BitAnd, + #[token("|")] + BitOr, + #[token("~")] + BitNot, + #[token("^")] + BitXor, + #[token(">>")] + ShiftR, + #[token("<<")] + ShiftL, + // Combined bitwise assignments + #[token("&=")] + BitAndAssign, + #[token("|=")] + BitOrAssign, + #[token("~=")] + BitNotAssign, + #[token("^=")] + BitXorAssign, + #[token(">>=")] + ShiftRAssign, + #[token("<<=")] + ShiftLAssign, + // Assign + #[token("=")] + Assign, + #[token("===")] + EqualSignal, + #[token("-->")] + LAssignSignal, + #[token("==>")] + LAssignContraintSignal, + #[token("<--")] + RAssignSignal, + #[token("<==")] + RAssignConstraintSignal, + // Conditional expressions + #[token("?")] + MarkQuestion, + #[token(":")] + Colon, + // Keywords + #[token("template")] + TemplateKw, + #[token("function")] + FunctionKw, + #[token("component")] + ComponentKw, + #[token("main")] + MainKw, + #[token("public")] + PublicKw, + #[token("signal")] + SignalKw, + #[token("var")] + VarKw, + #[token("include")] + IncludeKw, + #[token("input")] + InputKw, + #[token("output")] + OutputKw, + #[token("log")] + LogKw, + // Statement keywords + #[token("if")] + IfKw, + #[token("else")] + ElseKw, + #[token("for")] + ForKw, + #[token("while")] + WhileKw, + #[token("return")] + ReturnKw, + #[token("assert")] + AssertKw, + // Complex token kind + ForLoop, + AssignStatement, + CircomProgram, + SignalOfComponent, + SignalHeader, + Block, + Tuple, + TupleInit, + Call, + TenaryConditional, + Condition, + Expression, + FunctionDef, + Statement, + StatementList, + ComponentDecl, + TemplateDef, + TemplateName, + FunctionName, + ParameterList, + SignalDecl, + VarDecl, + InputSignalDecl, + OutputSignalDecl, + ComponentCall, + ComponentIdentifier, + SignalIdentifier, + ArrayQuery, + ParserError, + BlockComment, + EOF, + ROOT, + __LAST, +} + +impl From for TokenKind { + #[inline] + fn from(d: u16) -> TokenKind { + assert!(d <= (TokenKind::__LAST as u16)); + unsafe { std::mem::transmute::(d) } + } +} + +impl From for TokenKind { + fn from(value: rowan::SyntaxKind) -> Self { + match value { + rowan::SyntaxKind(id) => TokenKind::from(id), + } + } +} + +impl From for u16 { + #[inline] + fn from(k: TokenKind) -> u16 { + k as u16 + } +} + +impl From for rowan::SyntaxKind { + fn from(kind: TokenKind) -> Self { + Self(kind as u16) + } +} + +impl TokenKind { + // a + 10 --> a and 10 are literals + pub fn is_literal(self) -> bool { + matches!(self, Self::Number | Self::Identifier) + } + + // these tokens have the lowest priority + // infix_operator + // eg: a + b --> + is an infix token + pub fn infix(self) -> Option<(u16, u16)> { + match self { + // arithmetic operators + Self::Power => Some((99, 100)), + Self::Mul | Self::Div | Self::IntDiv | Self::Mod => Some((94, 95)), + Self::Add | Self::Sub => Some((89, 90)), + + // shift bitwise operators + Self::ShiftL | Self::ShiftR => Some((84, 85)), + + // relational operators + Self::LessThan + | Self::GreaterThan + | Self::LessThanAndEqual + | Self::GreaterThanAndEqual => Some((79, 80)), + Self::Equal + | Self::NotEqual => Some((74, 75)), + + // other bitwise operators + Self::BitAnd => Some((69, 70)), + Self::BitXor => Some((64, 65)), // exclusive or + Self::BitOr => Some((59, 60)), + + // boolean operators + Self::BoolAnd => Some((54, 55)), + Self::BoolOr => Some((49, 50)), + + // TODO: how about conditional operation ( ? : ) + // associativity: right to left [ a ? b : c --> ??? ] + + // associativity: right to left [ a = b = c --> a = (b = c) ] + // assignment operators + Self::Assign + // bitwise asignment operators + | Self::BitOrAssign + | Self::BitXorAssign + | Self::BitAndAssign + | Self::ShiftLAssign + | Self::ShiftRAssign + // arithmetic asignament operators + | Self::AddAssign + | Self::SubAssign + | Self::MulAssign + | Self::DivAssign + | Self::IntDivAssign + | Self::ModAssign + | Self::PowerAssign => Some((44, 45)), + + // TODO: how about comma (expression separator) + Self::Comma => Some((39, 40)), + + // not an infix operator + _ => None, + } + } + + // priority: post > pre > in + // associativity: right to left [ --!a --> --(!a) ] + // prefix_operator + // eg: -10, !a, ++a, --a + pub fn prefix(self) -> Option { + match self { + Self::UnitDec | Self::UnitInc + | Self::Sub | Self::Add + | Self::Not | Self::BitNot => Some(200), + + _ => None, + } + } + + // these tokens have the highest priority + // postfix_operator + // eg: a[10], b++, c.att1 + pub fn postfix(self) -> Option { + match self { + Self::LParen // function call + | Self::LBracket // array subscript + | Self::Dot // attribute access + | Self::UnitDec | Self::UnitInc => Some(300), + + _ => None, + } + } + + pub fn is_declaration_kw(self) -> bool { + matches!(self, Self::VarKw | Self::ComponentKw | Self::SignalKw) + } + + pub fn is_trivial(self) -> bool { + matches!( + self, + Self::WhiteSpace | Self::EndLine | Self::CommentLine | Self::BlockComment | Self::Error + ) + } +} diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index ded3cc3..1cea829 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -1,419 +1,419 @@ -use parser::input::Input; -use parser::output::{Child, Output}; -use parser::parser::Parser; -use parser::token_kind::TokenKind; -use rowan::{GreenNode, GreenNodeBuilder}; - -use crate::syntax_node::SyntaxNode; - -pub struct SyntaxTreeBuilder<'a> { - builder: GreenNodeBuilder<'static>, - input: &'a Input<'a>, -} - -impl<'a> SyntaxTreeBuilder<'a> { - pub fn new(input: &'a Input) -> Self { - Self { - builder: GreenNodeBuilder::new(), - input, - } - } - pub fn build_rec(&mut self, tree: &Output) { - self.builder.start_node(tree.kind().into()); - for child in tree.children() { - match child { - Child::Token(token_id) => { - let token_kind = self.input.kind_of(*token_id); - // TODO: return Error to replace .unwrap() - let token_value = self.input.token_value(*token_id).unwrap(); - self.builder.start_node(token_kind.into()); - self.builder.token(token_kind.into(), token_value); - self.builder.finish_node(); - } - Child::Tree(child_tree) => self.build_rec(child_tree), - Child::Error(error) => { - let token_kind = TokenKind::Error; - let token_value = error.as_str(); - - self.builder.start_node(token_kind.into()); - self.builder.token(token_kind.into(), token_value); - self.builder.finish_node(); - } - } - } - - self.builder.finish_node(); - } - - pub fn build(&mut self, tree: Output) { - self.build_rec(&tree); - } - - pub fn finish(self) -> GreenNode { - self.builder.finish() - } - - pub fn syntax_tree(source: &str) -> SyntaxNode { - let input = Input::new(source); - - let output = Parser::parsing(&input); - - let mut builder = SyntaxTreeBuilder::new(&input); - builder.build(output); - let green = builder.finish(); - SyntaxNode::new_root(green) - } -} - -#[cfg(test)] -mod tests { - use std::hash::{DefaultHasher, Hash, Hasher}; - - use rowan::ast::AstNode; - - use crate::{abstract_syntax_tree::AstCircomProgram, test_programs}; - - use super::SyntaxTreeBuilder; - - fn ast_from_source(source: &str) -> AstCircomProgram { - let syntax = SyntaxTreeBuilder::syntax_tree(source); - AstCircomProgram::cast(syntax).unwrap() - } - - fn children_from_ast(ast: &AstCircomProgram) -> Vec { - let children = ast - .syntax() - .first_child() - .unwrap() - .siblings(rowan::Direction::Next) - .into_iter() - .map(|child| child.text().to_string()) - .collect(); - - children - } - - fn pragma_string_from_ast(ast: &AstCircomProgram) -> String { - ast.pragma().unwrap().syntax().text().to_string() - } - - fn pragma_version_from_ast(ast: &AstCircomProgram) -> String { - ast.pragma() - .unwrap() - .version() - .unwrap() - .syntax() - .text() - .to_string() - } - - fn template_names_from_ast(ast: &AstCircomProgram) -> Vec { - let templates = ast - .template_list() - .iter() - .map(|template| template.name().unwrap().syntax().text().to_string()) - .collect(); - - templates - } - - fn function_names_from_ast(ast: &AstCircomProgram) -> Vec { - let functions = ast - .function_list() - .iter() - .map(|function| { - function - .function_name() - .unwrap() - .syntax() - .text() - .to_string() - }) - .collect(); - - functions - } - - #[test] - fn syntax_test_1() { - let ast = ast_from_source(test_programs::PARSER_TEST_1); - - // check_ast_children - let children = children_from_ast(&ast); - insta::assert_yaml_snapshot!("syntax_test_1_children", children); - - // check pragma - let pragma = pragma_string_from_ast(&ast); - insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - - // check ast hash - let mut hasher = DefaultHasher::default(); - ast.syntax().hash(&mut hasher); - let _ast_hash = hasher.finish(); - - // check template hash - let mut h1 = DefaultHasher::default(); - let mut h2 = DefaultHasher::default(); - - let template = ast.template_list(); - - template[0].syntax().hash(&mut h1); - template[1].syntax().hash(&mut h2); - - assert_ne!( - h1.finish(), - h2.finish(), - "Templates with same syntax should have different hashes!" - ); - - // check template syntax (text & green node) - assert_eq!( - template[0].syntax().text(), - template[1].syntax().text(), - "The syntax (as text) of template 1 and 2 must be the same!" - ); - assert_eq!( - template[0].syntax().green(), - template[1].syntax().green(), - "The syntax (as green node) of template 1 and 2 must be the same!!" - ); - } - - #[test] - fn syntax_test_2() { - let ast = ast_from_source(test_programs::PARSER_TEST_2); - - let pragma = pragma_string_from_ast(&ast); - insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - - let function_names = function_names_from_ast(&ast); - insta::assert_yaml_snapshot!("syntax_test_2_functions", function_names); - - let template_names = template_names_from_ast(&ast); - insta::assert_yaml_snapshot!("syntax_test_2_templates", template_names); - } - - #[test] - fn syntax_test_3() { - let ast = ast_from_source(test_programs::PARSER_TEST_3); - let pragma = pragma_string_from_ast(&ast); - insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - - let pragma_version = pragma_version_from_ast(&ast); - insta::assert_yaml_snapshot!(pragma_version, @"2.0.0"); - } - - #[test] - fn syntax_test_4() { - let ast = ast_from_source(test_programs::PARSER_TEST_4); - let pragma = pragma_string_from_ast(&ast); - insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); - - let pragma_version = pragma_version_from_ast(&ast); - insta::assert_yaml_snapshot!(pragma_version, @"2.0.0"); - } - - #[test] - fn syntax_test_5() { - let ast = ast_from_source(test_programs::PARSER_TEST_5); - let pragma = ast.pragma().is_none(); - insta::assert_yaml_snapshot!(pragma, @"true"); - - let template_names = template_names_from_ast(&ast); - insta::assert_yaml_snapshot!("syntax_test_5_templates", template_names); - } - - #[test] - fn syntax_test_6() { - let ast = ast_from_source(test_programs::PARSER_TEST_6); - let pragma = ast.pragma().is_none(); - insta::assert_yaml_snapshot!(pragma, @"true"); - - let template_names = template_names_from_ast(&ast); - insta::assert_yaml_snapshot!("syntax_test_6_templates", template_names); - } -} - -#[cfg(test)] -mod grammar_tests { - - use crate::{ - abstract_syntax_tree::{AstBlock, AstOutputSignalDecl, AstPragma, AstTemplateDef}, - syntax::SyntaxTreeBuilder, - syntax_node::CircomLanguage, - }; - use parser::{grammar::entry::Scope, input::Input, parser::Parser}; - use rowan::{ast::AstNode, SyntaxNode}; - - fn syntax_node_from_source(source: &str, scope: Scope) -> SyntaxNode { - let input = Input::new(&source); - let output = Parser::parsing_with_scope(&input, scope); - - // output is a tree whose node is index of token, no content of token - // convert output into green node - let mut builder = SyntaxTreeBuilder::new(&input); - builder.build(output); - let green = builder.finish(); - - // then cast green node into syntax node - let syntax = SyntaxNode::new_root(green); - - syntax - } - - #[test] - fn pragma_happy_test() { - // parse source (string) into output tree - let version = r#"2.0.1"#; - let source = format!(r#"pragma circom {};"#, version); - - let syntax = syntax_node_from_source(&source, Scope::Pragma); - - // cast syntax node into ast node to retrieve more information - let pragma = AstPragma::cast(syntax).expect("Can not cast syntax node into ast pragma"); - - // finally, assert with expect value - let pragma_versison_kind = pragma.version().unwrap().syntax().kind(); - insta::assert_yaml_snapshot!(pragma_versison_kind, @"Version"); - - let pragma_versison_text = pragma.version().unwrap().syntax().text().to_string(); - insta::assert_yaml_snapshot!(pragma_versison_text, @"2.0.1"); - } - - #[test] - fn template_happy_test() { - // SOURCE & EXPECTED RESULT - const SOURCE: &str = r#"template MultiplierN (N, P, QQ) { - //Declaration of signals and components. - signal input in[N]; - signal output out; - component comp[N-1]; - - //Statements. - for(var i = 0; i < N-1; i++){ - comp[i] = Multiplier2(); - } - - // ... some more code (see below) - - }"#; - - let syntax = syntax_node_from_source(&SOURCE, Scope::Template); - - // cast syntax node into ast node to retrieve more information - let template = - AstTemplateDef::cast(syntax).expect("Can not cast syntax node into ast template"); - - // finally, assert with expect value - - // name - let name = template - .name() - .expect("Can not extract template name") - .syntax() - .text() - .to_string(); - insta::assert_yaml_snapshot!(name, @"MultiplierN"); - - // parameter list - let first_param = template - .parameter_list() - .expect("Can not detect parameter list") - .syntax() - .first_child() - .unwrap() - .text() - .to_string(); - insta::assert_yaml_snapshot!(first_param, @"N"); - - let last_param = template - .parameter_list() - .expect("Can not detect parameter list") - .syntax() - .last_child() - .unwrap() - .text() - .to_string(); - insta::assert_yaml_snapshot!(last_param, @"QQ"); - - // statements - let statements = template.statements().unwrap(); - let output_signal = statements.find_children::(); - println!("{:?}", output_signal); - - let statements: Vec = statements - .statement_list() - .into_iter() - .map(|statement| statement.syntax().text().to_string()) - .collect(); - insta::assert_yaml_snapshot!("template_happy_test_statements", statements); - - // input signal - let input_signal = template - .find_input_signal("in") - .unwrap() - .syntax() - .text() - .to_string(); - insta::assert_yaml_snapshot!(input_signal, @"signal input in[N];"); - - // output signal - let output_signal = template - .find_output_signal("out") - .unwrap() - .syntax() - .text() - .to_string(); - insta::assert_yaml_snapshot!(output_signal, @"signal output out;"); - - // internal signal - let internal_signal = template.find_internal_signal("in").is_none(); - insta::assert_yaml_snapshot!(internal_signal, @"true"); - - // component - let component = template - .find_component("comp") - .unwrap() - .syntax() - .text() - .to_string(); - insta::assert_yaml_snapshot!(component, @"component comp[N-1];"); - } - - #[test] - fn block_happy_test() { - // SOURCE & EXPECTED RESULT - let source = r#"{ - //Declaration of signals. - signal input in[N]; - signal output out; - component comp[N-1]; - - //Statements. - for(var i = 0; i < N-1; i++){ - comp[i] = Multiplier2(); - } - comp[0].in1 <== in[0]; - comp[0].in2 <== in[1]; - for(var i = 0; i < N-2; i++){ - comp[i+1].in1 <== comp[i].out; - comp[i+1].in2 <== in[i+2]; - - } - out <== comp[N-2].out; - }"#; - - let syntax = syntax_node_from_source(&source, Scope::Block); - - // cast syntax node into ast node to retrieve more information - let block = AstBlock::cast(syntax).expect("Can not cast syntax node into ast block"); - - // finally, assert with expect statements - let statements = block.statement_list().unwrap().statement_list(); - let statements: Vec = statements - .into_iter() - .map(|statement| statement.syntax().text().to_string()) - .collect(); - insta::assert_yaml_snapshot!("block_happy_test_statements", statements); - } -} +use parser::input::Input; +use parser::output::{Child, Output}; +use parser::parser::Parser; +use parser::token_kind::TokenKind; +use rowan::{GreenNode, GreenNodeBuilder}; + +use crate::syntax_node::SyntaxNode; + +pub struct SyntaxTreeBuilder<'a> { + builder: GreenNodeBuilder<'static>, + input: &'a Input<'a>, +} + +impl<'a> SyntaxTreeBuilder<'a> { + pub fn new(input: &'a Input) -> Self { + Self { + builder: GreenNodeBuilder::new(), + input, + } + } + pub fn build_rec(&mut self, tree: &Output) { + self.builder.start_node(tree.kind().into()); + for child in tree.children() { + match child { + Child::Token(token_id) => { + let token_kind = self.input.kind_of(*token_id); + // TODO: return Error to replace .unwrap() + let token_value = self.input.token_value(*token_id).unwrap(); + self.builder.start_node(token_kind.into()); + self.builder.token(token_kind.into(), token_value); + self.builder.finish_node(); + } + Child::Tree(child_tree) => self.build_rec(child_tree), + Child::Error(error) => { + let token_kind = TokenKind::Error; + let token_value = error.as_str(); + + self.builder.start_node(token_kind.into()); + self.builder.token(token_kind.into(), token_value); + self.builder.finish_node(); + } + } + } + + self.builder.finish_node(); + } + + pub fn build(&mut self, tree: Output) { + self.build_rec(&tree); + } + + pub fn finish(self) -> GreenNode { + self.builder.finish() + } + + pub fn syntax_tree(source: &str) -> SyntaxNode { + let input = Input::new(source); + + let output = Parser::parsing(&input); + + let mut builder = SyntaxTreeBuilder::new(&input); + builder.build(output); + let green = builder.finish(); + SyntaxNode::new_root(green) + } +} + +#[cfg(test)] +mod tests { + use std::hash::{DefaultHasher, Hash, Hasher}; + + use rowan::ast::AstNode; + + use crate::{abstract_syntax_tree::AstCircomProgram, test_programs}; + + use super::SyntaxTreeBuilder; + + fn ast_from_source(source: &str) -> AstCircomProgram { + let syntax = SyntaxTreeBuilder::syntax_tree(source); + AstCircomProgram::cast(syntax).unwrap() + } + + fn children_from_ast(ast: &AstCircomProgram) -> Vec { + let children = ast + .syntax() + .first_child() + .unwrap() + .siblings(rowan::Direction::Next) + .into_iter() + .map(|child| child.text().to_string()) + .collect(); + + children + } + + fn pragma_string_from_ast(ast: &AstCircomProgram) -> String { + ast.pragma().unwrap().syntax().text().to_string() + } + + fn pragma_version_from_ast(ast: &AstCircomProgram) -> String { + ast.pragma() + .unwrap() + .version() + .unwrap() + .syntax() + .text() + .to_string() + } + + fn template_names_from_ast(ast: &AstCircomProgram) -> Vec { + let templates = ast + .template_list() + .iter() + .map(|template| template.name().unwrap().syntax().text().to_string()) + .collect(); + + templates + } + + fn function_names_from_ast(ast: &AstCircomProgram) -> Vec { + let functions = ast + .function_list() + .iter() + .map(|function| { + function + .function_name() + .unwrap() + .syntax() + .text() + .to_string() + }) + .collect(); + + functions + } + + #[test] + fn syntax_test_1() { + let ast = ast_from_source(test_programs::PARSER_TEST_1); + + // check_ast_children + let children = children_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_1_children", children); + + // check pragma + let pragma = pragma_string_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); + + // check ast hash + let mut hasher = DefaultHasher::default(); + ast.syntax().hash(&mut hasher); + let _ast_hash = hasher.finish(); + + // check template hash + let mut h1 = DefaultHasher::default(); + let mut h2 = DefaultHasher::default(); + + let template = ast.template_list(); + + template[0].syntax().hash(&mut h1); + template[1].syntax().hash(&mut h2); + + assert_ne!( + h1.finish(), + h2.finish(), + "Templates with same syntax should have different hashes!" + ); + + // check template syntax (text & green node) + assert_eq!( + template[0].syntax().text(), + template[1].syntax().text(), + "The syntax (as text) of template 1 and 2 must be the same!" + ); + assert_eq!( + template[0].syntax().green(), + template[1].syntax().green(), + "The syntax (as green node) of template 1 and 2 must be the same!!" + ); + } + + #[test] + fn syntax_test_2() { + let ast = ast_from_source(test_programs::PARSER_TEST_2); + + let pragma = pragma_string_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); + + let function_names = function_names_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_2_functions", function_names); + + let template_names = template_names_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_2_templates", template_names); + } + + #[test] + fn syntax_test_3() { + let ast = ast_from_source(test_programs::PARSER_TEST_3); + let pragma = pragma_string_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); + + let pragma_version = pragma_version_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma_version, @"2.0.0"); + } + + #[test] + fn syntax_test_4() { + let ast = ast_from_source(test_programs::PARSER_TEST_4); + let pragma = pragma_string_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma, @"pragma circom 2.0.0;"); + + let pragma_version = pragma_version_from_ast(&ast); + insta::assert_yaml_snapshot!(pragma_version, @"2.0.0"); + } + + #[test] + fn syntax_test_5() { + let ast = ast_from_source(test_programs::PARSER_TEST_5); + let pragma = ast.pragma().is_none(); + insta::assert_yaml_snapshot!(pragma, @"true"); + + let template_names = template_names_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_5_templates", template_names); + } + + #[test] + fn syntax_test_6() { + let ast = ast_from_source(test_programs::PARSER_TEST_6); + let pragma = ast.pragma().is_none(); + insta::assert_yaml_snapshot!(pragma, @"true"); + + let template_names = template_names_from_ast(&ast); + insta::assert_yaml_snapshot!("syntax_test_6_templates", template_names); + } +} + +#[cfg(test)] +mod grammar_tests { + + use crate::{ + abstract_syntax_tree::{AstBlock, AstOutputSignalDecl, AstPragma, AstTemplateDef}, + syntax::SyntaxTreeBuilder, + syntax_node::CircomLanguage, + }; + use parser::{grammar::entry::Scope, input::Input, parser::Parser}; + use rowan::{ast::AstNode, SyntaxNode}; + + fn syntax_node_from_source(source: &str, scope: Scope) -> SyntaxNode { + let input = Input::new(&source); + let output = Parser::parsing_with_scope(&input, scope); + + // output is a tree whose node is index of token, no content of token + // convert output into green node + let mut builder = SyntaxTreeBuilder::new(&input); + builder.build(output); + let green = builder.finish(); + + // then cast green node into syntax node + let syntax = SyntaxNode::new_root(green); + + syntax + } + + #[test] + fn pragma_happy_test() { + // parse source (string) into output tree + let version = r#"2.0.1"#; + let source = format!(r#"pragma circom {};"#, version); + + let syntax = syntax_node_from_source(&source, Scope::Pragma); + + // cast syntax node into ast node to retrieve more information + let pragma = AstPragma::cast(syntax).expect("Can not cast syntax node into ast pragma"); + + // finally, assert with expect value + let pragma_versison_kind = pragma.version().unwrap().syntax().kind(); + insta::assert_yaml_snapshot!(pragma_versison_kind, @"Version"); + + let pragma_versison_text = pragma.version().unwrap().syntax().text().to_string(); + insta::assert_yaml_snapshot!(pragma_versison_text, @"2.0.1"); + } + + #[test] + fn template_happy_test() { + // SOURCE & EXPECTED RESULT + const SOURCE: &str = r#"template MultiplierN (N, P, QQ) { + //Declaration of signals and components. + signal input in[N]; + signal output out; + component comp[N-1]; + + //Statements. + for(var i = 0; i < N-1; i++){ + comp[i] = Multiplier2(); + } + + // ... some more code (see below) + + }"#; + + let syntax = syntax_node_from_source(&SOURCE, Scope::Template); + + // cast syntax node into ast node to retrieve more information + let template = + AstTemplateDef::cast(syntax).expect("Can not cast syntax node into ast template"); + + // finally, assert with expect value + + // name + let name = template + .name() + .expect("Can not extract template name") + .syntax() + .text() + .to_string(); + insta::assert_yaml_snapshot!(name, @"MultiplierN"); + + // parameter list + let first_param = template + .parameter_list() + .expect("Can not detect parameter list") + .syntax() + .first_child() + .unwrap() + .text() + .to_string(); + insta::assert_yaml_snapshot!(first_param, @"N"); + + let last_param = template + .parameter_list() + .expect("Can not detect parameter list") + .syntax() + .last_child() + .unwrap() + .text() + .to_string(); + insta::assert_yaml_snapshot!(last_param, @"QQ"); + + // statements + let statements = template.statements().unwrap(); + let output_signal = statements.find_children::(); + println!("{:?}", output_signal); + + let statements: Vec = statements + .statement_list() + .into_iter() + .map(|statement| statement.syntax().text().to_string()) + .collect(); + insta::assert_yaml_snapshot!("template_happy_test_statements", statements); + + // input signal + let input_signal = template + .find_input_signal("in") + .unwrap() + .syntax() + .text() + .to_string(); + insta::assert_yaml_snapshot!(input_signal, @"signal input in[N];"); + + // output signal + let output_signal = template + .find_output_signal("out") + .unwrap() + .syntax() + .text() + .to_string(); + insta::assert_yaml_snapshot!(output_signal, @"signal output out;"); + + // internal signal + let internal_signal = template.find_internal_signal("in").is_none(); + insta::assert_yaml_snapshot!(internal_signal, @"true"); + + // component + let component = template + .find_component("comp") + .unwrap() + .syntax() + .text() + .to_string(); + insta::assert_yaml_snapshot!(component, @"component comp[N-1];"); + } + + #[test] + fn block_happy_test() { + // SOURCE & EXPECTED RESULT + let source = r#"{ + //Declaration of signals. + signal input in[N]; + signal output out; + component comp[N-1]; + + //Statements. + for(var i = 0; i < N-1; i++){ + comp[i] = Multiplier2(); + } + comp[0].in1 <== in[0]; + comp[0].in2 <== in[1]; + for(var i = 0; i < N-2; i++){ + comp[i+1].in1 <== comp[i].out; + comp[i+1].in2 <== in[i+2]; + + } + out <== comp[N-2].out; + }"#; + + let syntax = syntax_node_from_source(&source, Scope::Block); + + // cast syntax node into ast node to retrieve more information + let block = AstBlock::cast(syntax).expect("Can not cast syntax node into ast block"); + + // finally, assert with expect statements + let statements = block.statement_list().unwrap().statement_list(); + let statements: Vec = statements + .into_iter() + .map(|statement| statement.syntax().text().to_string()) + .collect(); + insta::assert_yaml_snapshot!("block_happy_test_statements", statements); + } +} From 84e960b229635b28a5ae7c6354c41c5ee09e650f Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 13:12:03 +0700 Subject: [PATCH 37/59] fix clippy check --- crates/parser/src/input.rs | 2 +- crates/parser/src/token_kind.rs | 22 ++++++++-------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index f22d611..57e7317 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -166,6 +166,6 @@ mod tests { & &= | |= }"#; - test(source, "test_operators"); + test(source, "test_operators"); } } diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 98ef766..974fc8e 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -268,10 +268,8 @@ impl TokenKind { Self::Power => Some((99, 100)), Self::Mul | Self::Div | Self::IntDiv | Self::Mod => Some((94, 95)), Self::Add | Self::Sub => Some((89, 90)), - // shift bitwise operators Self::ShiftL | Self::ShiftR => Some((84, 85)), - // relational operators Self::LessThan | Self::GreaterThan @@ -279,19 +277,17 @@ impl TokenKind { | Self::GreaterThanAndEqual => Some((79, 80)), Self::Equal | Self::NotEqual => Some((74, 75)), - // other bitwise operators Self::BitAnd => Some((69, 70)), Self::BitXor => Some((64, 65)), // exclusive or Self::BitOr => Some((59, 60)), - // boolean operators Self::BoolAnd => Some((54, 55)), Self::BoolOr => Some((49, 50)), - + // ---------- // TODO: how about conditional operation ( ? : ) // associativity: right to left [ a ? b : c --> ??? ] - + // ---------- // associativity: right to left [ a = b = c --> a = (b = c) ] // assignment operators Self::Assign @@ -307,26 +303,24 @@ impl TokenKind { | Self::MulAssign | Self::DivAssign | Self::IntDivAssign - | Self::ModAssign + | Self::ModAssign | Self::PowerAssign => Some((44, 45)), - // TODO: how about comma (expression separator) Self::Comma => Some((39, 40)), - // not an infix operator _ => None, } } // priority: post > pre > in - // associativity: right to left [ --!a --> --(!a) ] + // associativity: right to left [ --!a --> --(!a) ] // prefix_operator // eg: -10, !a, ++a, --a pub fn prefix(self) -> Option { match self { - Self::UnitDec | Self::UnitInc - | Self::Sub | Self::Add - | Self::Not | Self::BitNot => Some(200), + Self::UnitDec | Self::UnitInc | Self::Sub | Self::Add | Self::Not | Self::BitNot => { + Some(200) + } _ => None, } @@ -340,7 +334,7 @@ impl TokenKind { Self::LParen // function call | Self::LBracket // array subscript | Self::Dot // attribute access - | Self::UnitDec | Self::UnitInc => Some(300), + | Self::UnitDec | Self::UnitInc => Some(300), _ => None, } From a1bd25e86d19ae1ced5813b14df1f742dc9e0157 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 13:22:38 +0700 Subject: [PATCH 38/59] fix clippy --- crates/lsp/src/handler/goto_definition.rs | 1 - crates/parser/src/grammar/declaration.rs | 1 - crates/parser/src/grammar/expression.rs | 1 - crates/parser/src/grammar/statement.rs | 3 --- crates/parser/src/grammar/template.rs | 1 - crates/syntax/src/syntax.rs | 1 - 6 files changed, 8 deletions(-) diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 4c7e1f0..4cba681 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -229,7 +229,6 @@ template Y() { let syntax_node = SyntaxTreeBuilder::syntax_tree(&source); - if let Some(program_ast) = AstCircomProgram::cast(syntax_node) { for template in program_ast.template_list() { println!("{template:?}"); diff --git a/crates/parser/src/grammar/declaration.rs b/crates/parser/src/grammar/declaration.rs index 0ee9d61..c5dd125 100644 --- a/crates/parser/src/grammar/declaration.rs +++ b/crates/parser/src/grammar/declaration.rs @@ -128,4 +128,3 @@ pub(super) fn declaration(p: &mut Parser) { _ => unreachable!(), } } - diff --git a/crates/parser/src/grammar/expression.rs b/crates/parser/src/grammar/expression.rs index 9beee8f..4604da4 100644 --- a/crates/parser/src/grammar/expression.rs +++ b/crates/parser/src/grammar/expression.rs @@ -156,4 +156,3 @@ fn circom_expression(p: &mut Parser) { } } } - diff --git a/crates/parser/src/grammar/statement.rs b/crates/parser/src/grammar/statement.rs index fca6007..626600d 100644 --- a/crates/parser/src/grammar/statement.rs +++ b/crates/parser/src/grammar/statement.rs @@ -82,7 +82,6 @@ fn for_statement(p: &mut Parser) { p.close(m, ForLoop); } -/* /* while () @@ -95,7 +94,6 @@ fn while_statement(p: &mut Parser) { statement(p); } -/* /* assert() */ @@ -185,4 +183,3 @@ fn assignment_statement(p: &mut Parser) { p.close(m, Error); } } - diff --git a/crates/parser/src/grammar/template.rs b/crates/parser/src/grammar/template.rs index bb599b6..a502365 100644 --- a/crates/parser/src/grammar/template.rs +++ b/crates/parser/src/grammar/template.rs @@ -23,4 +23,3 @@ pub fn template(p: &mut Parser) { p.close(m, TemplateDef); } - diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 5edce00..2b303a7 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -300,7 +300,6 @@ mod grammar_tests { let syntax = syntax_node_from_source(&SOURCE, Scope::Template); - // cast syntax node into ast node to retrieve more information let template = AstTemplateDef::cast(syntax).expect("Can not cast syntax node into ast template"); From 3a0879787083551a974fc6b75a26c2aee894c0ba Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 15:06:42 +0700 Subject: [PATCH 39/59] remove duplicate declaration in grammar tests --- crates/syntax/src/syntax.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 2b303a7..ded3cc3 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -349,12 +349,6 @@ mod grammar_tests { insta::assert_yaml_snapshot!("template_happy_test_statements", statements); // input signal - let input_signal = template - .find_input_signal("in") - .unwrap() - .syntax() - .text() - .to_string(); let input_signal = template .find_input_signal("in") .unwrap() @@ -364,12 +358,6 @@ mod grammar_tests { insta::assert_yaml_snapshot!(input_signal, @"signal input in[N];"); // output signal - let output_signal = template - .find_output_signal("out") - .unwrap() - .syntax() - .text() - .to_string(); let output_signal = template .find_output_signal("out") .unwrap() @@ -383,12 +371,6 @@ mod grammar_tests { insta::assert_yaml_snapshot!(internal_signal, @"true"); // component - let component = template - .find_component("comp") - .unwrap() - .syntax() - .text() - .to_string(); let component = template .find_component("comp") .unwrap() From 39f1e12d515dea3101c7e9851fdab8042561ac91 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 17:06:25 +0700 Subject: [PATCH 40/59] add missing signal assign tokens --- crates/parser/src/token_kind.rs | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index 2101ef9..aa89ac0 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -293,6 +293,12 @@ impl TokenKind { // associativity: right to left [ a = b = c --> a = (b = c) ] // assignment operators Self::Assign + // signal assigment operators + | Self::EqualSignal + | Self::LAssignSignal + | Self::LAssignContraintSignal + | Self::RAssignSignal + | Self::RAssignConstraintSignal // bitwise asignment operators | Self::BitOrAssign | Self::BitXorAssign @@ -346,6 +352,36 @@ impl TokenKind { matches!(self, Self::VarKw | Self::ComponentKw | Self::SignalKw) } + pub fn is_assign_token(self) -> bool { + matches!( + self, + Self::Assign + // signal assigment operators + | Self::EqualSignal + | Self::LAssignSignal + | Self::LAssignContraintSignal + | Self::RAssignSignal + | Self::RAssignConstraintSignal + // bitwise asignment operators + | Self::BitOrAssign + | Self::BitXorAssign + | Self::BitAndAssign + | Self::ShiftLAssign + | Self::ShiftRAssign + // arithmetic asignament operators + | Self::AddAssign + | Self::SubAssign + | Self::MulAssign + | Self::DivAssign + | Self::IntDivAssign + | Self::ModAssign + | Self::PowerAssign + // unit inc/dec + | Self::UnitInc + | Self::UnitDec + ) + } + pub fn is_trivial(self) -> bool { matches!( self, From f4db959acaaadb061c63f7e495499068d63492d4 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 17:06:55 +0700 Subject: [PATCH 41/59] fix grammar of for statement --- crates/parser/src/grammar/block.rs | 1 + crates/parser/src/grammar/expression.rs | 12 +++++-- crates/parser/src/grammar/statement.rs | 36 +++++++++++++------ crates/parser/src/parser.rs | 5 +++ ...mmar_tests__for_happy_test_statements.snap | 9 +++++ crates/syntax/src/syntax.rs | 30 ++++++++++++++++ 6 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 crates/syntax/src/snapshots/syntax__syntax__grammar_tests__for_happy_test_statements.snap diff --git a/crates/parser/src/grammar/block.rs b/crates/parser/src/grammar/block.rs index f01b515..645632d 100644 --- a/crates/parser/src/grammar/block.rs +++ b/crates/parser/src/grammar/block.rs @@ -11,6 +11,7 @@ use super::*; pub fn block(p: &mut Parser) { p.inc_rcurly(); + // TODO: why do not use expect for { and } if !p.at(LCurly) { p.advance_with_error("Miss {"); } else { diff --git a/crates/parser/src/grammar/expression.rs b/crates/parser/src/grammar/expression.rs index 4604da4..e0a2d7a 100644 --- a/crates/parser/src/grammar/expression.rs +++ b/crates/parser/src/grammar/expression.rs @@ -10,15 +10,21 @@ pub(super) fn expression(p: &mut Parser) { /** * grammar: "(Symbol_1, Symbol_2,..., Symbol_n)" + * can be an empty tuple (for function cal: Mul()) */ pub(super) fn tuple(p: &mut Parser) { let m = p.open(); p.expect(LParen); - p.expect(Identifier); - while p.at(Comma) && !p.eof() { - p.expect(Comma); + + if p.at(Identifier) { p.expect(Identifier); + + while p.at(Comma) && !p.eof() { + p.expect(Comma); + p.expect(Identifier); + } } + p.expect(RParen); p.close(m, Tuple); } diff --git a/crates/parser/src/grammar/statement.rs b/crates/parser/src/grammar/statement.rs index 626600d..27de3c6 100644 --- a/crates/parser/src/grammar/statement.rs +++ b/crates/parser/src/grammar/statement.rs @@ -1,3 +1,5 @@ +use crate::token_kind::TokenKind; + use super::{block::block, expression::expression, *}; pub(super) fn statement(p: &mut Parser) { @@ -64,21 +66,31 @@ for (/; ; ) */ fn for_statement(p: &mut Parser) { let m = p.open(); + + // for ( p.expect(ForKw); p.expect(LParen); + if p.current().is_declaration_kw() { + // for (var i = 1 declaration::declaration(p); } else { + // for (i = 1 assignment_statement(p); } p.expect(Semicolon); + + // for (i = 1; i < N; expression::expression(p); p.expect(Semicolon); + // for (i = 1; i < N; i++) assignment_statement(p); p.expect(RParen); - statement_no_condition(p); + // for (i = 1; i < N; i++) { } + statement(p); + // statement_no_condition(p); p.close(m, ForLoop); } @@ -149,35 +161,39 @@ fn assignment_statement(p: &mut Parser) { if p.at(Identifier) { let m_id = p.open(); + // abc let m_name = p.open(); p.expect(Identifier); p.close(m_name, ComponentIdentifier); + + // abc[N - 1] if p.at(LBracket) { p.expect(LBracket); expression(p); p.expect(RBracket); } + if p.at(Dot) { + // abc[N - 1].def OR abc.def --> component call p.expect(Dot); p.expect(Identifier); p.close(m_id, ComponentCall); } else { + // abc[N - 1] OR abc --> expression p.close(m_id, Expression); } } else { + // assignment without identifier expression(p); } - if p.at_any(&[ - Assign, - RAssignSignal, - RAssignConstraintSignal, - LAssignContraintSignal, - LAssignSignal, - EqualSignal, - ]) { + // assign part + if p.at_assign_token() { + let is_self_assign = p.at_any(&[TokenKind::UnitDec, TokenKind::UnitInc]); p.advance(); - expression(p); + if is_self_assign == false { + expression(p); + } p.close(m, AssignStatement); } else { p.close(m, Error); diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index 34a2f64..9188176 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -166,6 +166,11 @@ impl<'a> Parser<'a> { kinds.contains(¤t_kind) } + pub fn at_assign_token(&mut self) -> bool { + let current_kind = self.current(); + current_kind.is_assign_token() + } + pub fn skip(&mut self) { self.next(); } diff --git a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__for_happy_test_statements.snap b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__for_happy_test_statements.snap new file mode 100644 index 0000000..ee362e6 --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__for_happy_test_statements.snap @@ -0,0 +1,9 @@ +--- +source: crates/syntax/src/syntax.rs +expression: statements +--- +- "for(var i = 0; i < N-1; i++){\n comp[i] = Multiplier2();\n }" +- "comp[0].in1 <== in[0];" +- "comp[0].in2 <== in[1];" +- "for(var i = 0; i < N-2; i++){\n comp[i+1].in1 <== comp[i].out;\n comp[i+1].in2 <== in[i+2];\n\n }" +- "out <== comp[N-2].out;" diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index ded3cc3..b4ae9d4 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -416,4 +416,34 @@ mod grammar_tests { .collect(); insta::assert_yaml_snapshot!("block_happy_test_statements", statements); } + + #[test] + fn for_happy_test() { + let source = r#"{ + //Statements. + for(var i = 0; i < N-1; i++){ + comp[i] = Multiplier2(); + } + comp[0].in1 <== in[0]; + comp[0].in2 <== in[1]; + for(var i = 0; i < N-2; i++){ + comp[i+1].in1 <== comp[i].out; + comp[i+1].in2 <== in[i+2]; + + } + out <== comp[N-2].out; + }"#; + + let syntax = syntax_node_from_source(&source, Scope::Block); + + // cast syntax node into ast node to retrieve more information + let block = AstBlock::cast(syntax).expect("Can not cast syntax node into ast block"); + + let statements = block.statement_list().unwrap().statement_list(); + let statements: Vec = statements + .into_iter() + .map(|statement| statement.syntax().text().to_string()) + .collect(); + insta::assert_yaml_snapshot!("for_happy_test_statements", statements); + } } From a9edb76067baa38ce56eb5933fb54bea9ff57f76 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 17:18:37 +0700 Subject: [PATCH 42/59] add statements test --- crates/parser/src/grammar/statement.rs | 1 - ...ests__statement_happy_test_statements.snap | 14 +++++++++++++ crates/syntax/src/syntax.rs | 21 +++++++++++++++++-- 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 crates/syntax/src/snapshots/syntax__syntax__grammar_tests__statement_happy_test_statements.snap diff --git a/crates/parser/src/grammar/statement.rs b/crates/parser/src/grammar/statement.rs index 27de3c6..39f8894 100644 --- a/crates/parser/src/grammar/statement.rs +++ b/crates/parser/src/grammar/statement.rs @@ -14,7 +14,6 @@ pub(super) fn statement(p: &mut Parser) { /* if (expr) -else else */ diff --git a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__statement_happy_test_statements.snap b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__statement_happy_test_statements.snap new file mode 100644 index 0000000..176aeed --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__statement_happy_test_statements.snap @@ -0,0 +1,14 @@ +--- +source: crates/syntax/src/syntax.rs +expression: statements +--- +- "for(var i = 0; i < N-1; i++){\n comp[i] = Multiplier2();\n }" +- "comp[0].in1 <== in[0];" +- "comp[0].in2 <== in[1];" +- "for(var i = 0; i < N-2; i++){\n comp[i+1].in1 <== comp[i].out;\n comp[i+1].in2 <== in[i+2];\n\n }" +- "out <== comp[N-2].out;" +- "while (out) {\n for(var i = 0; i < N-1; i++){\n comp[i] = Multiplier2();\n }\n }" +- assert(comp); +- "log(\"Print something...\", out);" +- "if (1 < 2) {\n log(\"Match...\", 1 < 2);\n } else {\n log(\"Does not match...\", 1 < 2);\n }" +- return out + comp; diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index b4ae9d4..568fbbb 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -418,7 +418,7 @@ mod grammar_tests { } #[test] - fn for_happy_test() { + fn statement_happy_test() { let source = r#"{ //Statements. for(var i = 0; i < N-1; i++){ @@ -432,6 +432,23 @@ mod grammar_tests { } out <== comp[N-2].out; + + // just for testing statement + while (out) { + for(var i = 0; i < N-1; i++){ + comp[i] = Multiplier2(); + } + } + assert(comp); + log("Print something...", out); + + if (1 < 2) { + log("Match...", 1 < 2); + } else { + log("Does not match...", 1 < 2); + } + + return out + comp; }"#; let syntax = syntax_node_from_source(&source, Scope::Block); @@ -444,6 +461,6 @@ mod grammar_tests { .into_iter() .map(|statement| statement.syntax().text().to_string()) .collect(); - insta::assert_yaml_snapshot!("for_happy_test_statements", statements); + insta::assert_yaml_snapshot!("statement_happy_test_statements", statements); } } From c5a17c3a9598d8a2bf79d7a1f6f748a30e1cf8e4 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 19:04:46 +0700 Subject: [PATCH 43/59] fix declaration, support matrix --- crates/lsp/src/handler/goto_definition.rs | 6 +- crates/parser/src/grammar/declaration.rs | 55 ++++++++++++------- .../src/abstract_syntax_tree/template.rs | 4 +- ...ar_tests__block_happy_test_statements.snap | 5 +- ...tests__template_happy_test_statements.snap | 5 +- crates/syntax/src/syntax.rs | 8 ++- 6 files changed, 46 insertions(+), 37 deletions(-) diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 4cba681..8609b4c 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -189,7 +189,7 @@ mod tests { pragma circom 2.0.0; template X() { - signal x = 10; + signal x[100]; signal input x = 10; component x = Multiplier2(); component y = X(); @@ -230,9 +230,7 @@ template Y() { let syntax_node = SyntaxTreeBuilder::syntax_tree(&source); if let Some(program_ast) = AstCircomProgram::cast(syntax_node) { - for template in program_ast.template_list() { - println!("{template:?}"); - } + println!("program: {}", program_ast.syntax().text().to_string()); let inputs = program_ast.template_list()[0] .func_body() diff --git a/crates/parser/src/grammar/declaration.rs b/crates/parser/src/grammar/declaration.rs index c5dd125..1d01c90 100644 --- a/crates/parser/src/grammar/declaration.rs +++ b/crates/parser/src/grammar/declaration.rs @@ -1,5 +1,5 @@ use super::{ - expression::{tuple, tuple_init}, + expression::{expression, tuple, tuple_init}, *, }; @@ -45,7 +45,7 @@ pub(super) fn var_declaration(p: &mut Parser) { p.expect(Identifier); if p.at(Assign) { p.expect(Assign); - expression::expression(p); + expression(p); } // list of var while p.at(Comma) && !p.eof() { @@ -53,13 +53,30 @@ pub(super) fn var_declaration(p: &mut Parser) { p.expect(Identifier); if p.at(Assign) { p.expect(Assign); - expression::expression(p); + expression(p); } } } p.close(m, VarDecl); } +pub(crate) fn signal_init(p: &mut Parser) { + // let m_c = p.open(); + p.expect(Identifier); + // p.close(m_c, SignalIdentifier); + + while p.at(LBracket) { + p.expect(LBracket); + expression(p); + p.expect(RBracket); + } + + if p.at_any(&[Assign, RAssignSignal, RAssignConstraintSignal]) { + p.advance(); + expression(p); + } +} + pub(super) fn signal_declaration(p: &mut Parser) { if !p.at(SignalKw) { p.advance_with_error("Signal error"); @@ -69,17 +86,18 @@ pub(super) fn signal_declaration(p: &mut Parser) { let m = p.open(); let io_signal = signal_header(p); + // tuple of signal if p.at(LParen) { tuple(p); if p.at_any(&[Assign, RAssignSignal, RAssignConstraintSignal]) { tuple_init(p); } } else { - p.expect(Identifier); - // list of var + // list of signal + signal_init(p); while p.at(Comma) && !p.eof() { p.skip(); - p.expect(Identifier); + signal_init(p); } } @@ -100,22 +118,19 @@ pub(super) fn component_declaration(p: &mut Parser) { let m_c = p.open(); p.expect(Identifier); p.close(m_c, ComponentIdentifier); - - p.expect(Assign); - let m_c = p.open(); - p.expect(Identifier); - p.close(m_c, TemplateName); - p.expect(LParen); - - if p.at(Identifier) { - expression::expression(p); - while !p.at(RParen) && !p.eof() { - p.expect(Comma); - expression::expression(p); - } + while p.at(LBracket) { + p.expect(LBracket); + expression(p); + p.expect(RBracket); } - p.expect(RParen); + if p.at(Assign) { + p.expect(Assign); + let m_c = p.open(); + p.expect(Identifier); + p.close(m_c, TemplateName); + tuple(p); + } p.close(m, ComponentDecl); } diff --git a/crates/syntax/src/abstract_syntax_tree/template.rs b/crates/syntax/src/abstract_syntax_tree/template.rs index 7253b12..e5db4ca 100644 --- a/crates/syntax/src/abstract_syntax_tree/template.rs +++ b/crates/syntax/src/abstract_syntax_tree/template.rs @@ -86,8 +86,8 @@ impl AstTemplateDef { pub fn find_component(&self, name: &str) -> Option { if let Some(statements) = self.statements() { for component in statements.find_children::() { - if let Some(signal_name) = component.component_identifier() { - if let Some(component_name) = signal_name.name() { + if let Some(component_identifier) = component.component_identifier() { + if let Some(component_name) = component_identifier.name() { if component_name.syntax().text() == name { return Some(component); } diff --git a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__block_happy_test_statements.snap b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__block_happy_test_statements.snap index 5db6859..ee362e6 100644 --- a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__block_happy_test_statements.snap +++ b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__block_happy_test_statements.snap @@ -2,11 +2,8 @@ source: crates/syntax/src/syntax.rs expression: statements --- -- "signal input in[N];" -- "signal output out;" -- "component comp[N-1];" - "for(var i = 0; i < N-1; i++){\n comp[i] = Multiplier2();\n }" - "comp[0].in1 <== in[0];" - "comp[0].in2 <== in[1];" - "for(var i = 0; i < N-2; i++){\n comp[i+1].in1 <== comp[i].out;\n comp[i+1].in2 <== in[i+2];\n\n }" -- "out <== comp[N-2].out;" \ No newline at end of file +- "out <== comp[N-2].out;" diff --git a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__template_happy_test_statements.snap b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__template_happy_test_statements.snap index 74cf89f..a84d4cc 100644 --- a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__template_happy_test_statements.snap +++ b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__template_happy_test_statements.snap @@ -2,7 +2,4 @@ source: crates/syntax/src/syntax.rs expression: statements --- -- "signal input in[N];" -- "signal output out;" -- "component comp[N-1];" -- "for(var i = 0; i < N-1; i++){\n comp[i] = Multiplier2();\n }" +- "for(var i = 0; i < N-1; i++){\n comp[i] = Multiplier2();\n }" diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 568fbbb..2484c0a 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -355,7 +355,7 @@ mod grammar_tests { .syntax() .text() .to_string(); - insta::assert_yaml_snapshot!(input_signal, @"signal input in[N];"); + insta::assert_yaml_snapshot!(input_signal, @r###""signal input in[N]""###); // output signal let output_signal = template @@ -364,7 +364,7 @@ mod grammar_tests { .syntax() .text() .to_string(); - insta::assert_yaml_snapshot!(output_signal, @"signal output out;"); + insta::assert_yaml_snapshot!(output_signal, @"signal output out"); // internal signal let internal_signal = template.find_internal_signal("in").is_none(); @@ -377,7 +377,7 @@ mod grammar_tests { .syntax() .text() .to_string(); - insta::assert_yaml_snapshot!(component, @"component comp[N-1];"); + insta::assert_yaml_snapshot!(component, @r###""component comp[N-1]""###); } #[test] @@ -408,6 +408,8 @@ mod grammar_tests { // cast syntax node into ast node to retrieve more information let block = AstBlock::cast(syntax).expect("Can not cast syntax node into ast block"); + println!("block: {}", block.syntax().text().to_string()); + // finally, assert with expect statements let statements = block.statement_list().unwrap().statement_list(); let statements: Vec = statements From 605c16b2dc15c7c8335c09da18fb406dc06c0998 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Mon, 30 Dec 2024 19:06:19 +0700 Subject: [PATCH 44/59] fix format --- crates/parser/src/grammar/expression.rs | 4 ++-- crates/parser/src/grammar/statement.rs | 2 +- crates/syntax/src/syntax.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/parser/src/grammar/expression.rs b/crates/parser/src/grammar/expression.rs index e0a2d7a..bfc9ab0 100644 --- a/crates/parser/src/grammar/expression.rs +++ b/crates/parser/src/grammar/expression.rs @@ -18,13 +18,13 @@ pub(super) fn tuple(p: &mut Parser) { if p.at(Identifier) { p.expect(Identifier); - + while p.at(Comma) && !p.eof() { p.expect(Comma); p.expect(Identifier); } } - + p.expect(RParen); p.close(m, Tuple); } diff --git a/crates/parser/src/grammar/statement.rs b/crates/parser/src/grammar/statement.rs index 39f8894..ee7d430 100644 --- a/crates/parser/src/grammar/statement.rs +++ b/crates/parser/src/grammar/statement.rs @@ -164,7 +164,7 @@ fn assignment_statement(p: &mut Parser) { let m_name = p.open(); p.expect(Identifier); p.close(m_name, ComponentIdentifier); - + // abc[N - 1] if p.at(LBracket) { p.expect(LBracket); diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 2484c0a..e233d7a 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -409,7 +409,7 @@ mod grammar_tests { let block = AstBlock::cast(syntax).expect("Can not cast syntax node into ast block"); println!("block: {}", block.syntax().text().to_string()); - + // finally, assert with expect statements let statements = block.statement_list().unwrap().statement_list(); let statements: Vec = statements From c9d93f7cce3f70fe689aeda65345921dd8ed4312 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 31 Dec 2024 11:33:33 +0700 Subject: [PATCH 45/59] refactor declaration --- crates/parser/src/grammar/declaration.rs | 182 +++++++++++++++-------- crates/parser/src/parser.rs | 10 ++ crates/parser/src/token_kind.rs | 11 ++ 3 files changed, 138 insertions(+), 65 deletions(-) diff --git a/crates/parser/src/grammar/declaration.rs b/crates/parser/src/grammar/declaration.rs index 1d01c90..7e56504 100644 --- a/crates/parser/src/grammar/declaration.rs +++ b/crates/parser/src/grammar/declaration.rs @@ -3,81 +3,119 @@ use super::{ *, }; -// "signal" --> None -// "signal input" --> Some(true) -// "signal output" --> Some(false) +// [N][M-1] +fn array(p: &mut Parser) -> bool { + let is_array = p.at(LBracket); + + while p.at(LBracket) { + p.expect(LBracket); + expression(p); + p.expect(RBracket); + } + + is_array +} + +/* +"signal" --> None +"signal input" --> Some(true) +"signal output" --> Some(false) +*/ fn signal_header(p: &mut Parser) -> Option { - let mut res = None; let m = p.open(); p.expect(SignalKw); - if p.at_any(&[InputKw, OutputKw]) { - if p.at(InputKw) { - res = Some(true); - } else { - res = Some(false); - } + + let res = if p.at(InputKw) { + Some(true) + } else if p.at(OutputKw) { + Some(false) + } else { + None + }; + + if res.is_some() { p.advance(); + } - if p.at(LCurly) { - p.expect(Identifier); - p.expect(RCurly); - } + // signal tags + // {tag1, tag2, tag2} + // TODO: support list of tags + if p.at(LCurly) { + p.expect(Identifier); + p.expect(RCurly); } + p.close(m, SignalHeader); res } +pub(crate) fn var_init(p: &mut Parser) { + // name of variable + p.expect(Identifier); + + // eg: [N - 1][M] + array(p); + + // assign for variable + // eg: = 10 + if p.at_var_assign() { + p.advance(); + expression(p); + } +} + +// eg: in[N - 1] <== c.in; +pub(crate) fn signal_init(p: &mut Parser, assign_able: bool) { + // name of signal + p.expect(Identifier); + + // eg: [N][M-1] + array(p); + + // assign for intermediate and outputs signals + // eg: <== Multiplier2().out + if assign_able && p.at_inline_assign_signal() { + p.advance(); + expression(p); + } +} + /** * Declaration := "var" (SimpleSymbol, ..., SimpleSymbol) TupleInitialization | - * - * + * "var" iden1 = init1, iden2 = init2, iden3 */ pub(super) fn var_declaration(p: &mut Parser) { let m = p.open(); p.expect(VarKw); + // tuple of variables + // eg: var (in1, in2, in3) = (1, 2, 3); if p.at(LParen) { tuple(p); - if p.at(Assign) { + if p.at_var_assign() { tuple_init(p); } } else { - p.expect(Identifier); - if p.at(Assign) { - p.expect(Assign); - expression(p); - } - // list of var + // list of variables + // var in1[N], in2 = 5; + var_init(p); while p.at(Comma) && !p.eof() { - p.expect(Comma); - p.expect(Identifier); - if p.at(Assign) { - p.expect(Assign); - expression(p); - } + p.skip(); + var_init(p); } } - p.close(m, VarDecl); -} - -pub(crate) fn signal_init(p: &mut Parser) { - // let m_c = p.open(); - p.expect(Identifier); - // p.close(m_c, SignalIdentifier); - - while p.at(LBracket) { - p.expect(LBracket); - expression(p); - p.expect(RBracket); - } - if p.at_any(&[Assign, RAssignSignal, RAssignConstraintSignal]) { - p.advance(); - expression(p); - } + p.close(m, VarDecl); } +/* +* signal are immutable (can not modify after init value) +* can not initialize value for input signal +* since circom 2.0.4, it is also allowed to initialize +intermediate and outputs signals right after their declaration +*/ pub(super) fn signal_declaration(p: &mut Parser) { + // TODO: can we remove that? if !p.at(SignalKw) { p.advance_with_error("Signal error"); return; @@ -85,50 +123,64 @@ pub(super) fn signal_declaration(p: &mut Parser) { let m = p.open(); let io_signal = signal_header(p); + let assign_able = io_signal != Some(true); // tuple of signal + // eg: signal (in1, in2, in3) <== tuple_value; if p.at(LParen) { tuple(p); - if p.at_any(&[Assign, RAssignSignal, RAssignConstraintSignal]) { + // can not assign for input signal + if assign_able && p.at_inline_assign_signal() { tuple_init(p); } } else { - // list of signal - signal_init(p); + // list of signals + // signal in1[N], in2 <== signal_value; + signal_init(p, assign_able); while p.at(Comma) && !p.eof() { p.skip(); - signal_init(p); + signal_init(p, assign_able); } } - if let Some(is_input) = io_signal { - if is_input { - p.close(m, InputSignalDecl); - } else { - p.close(m, OutputSignalDecl); - } - } else { - p.close(m, SignalDecl); - } + let close_kind = match io_signal { + Some(true) => InputSignalDecl, + Some(false) => OutputSignalDecl, + None => SignalDecl, + }; + + p.close(m, close_kind); } +/* +* initialization in the definition of arrays of components is not allowed +*/ pub(super) fn component_declaration(p: &mut Parser) { let m = p.open(); p.expect(ComponentKw); + + // TODO: why do we need `ComponentIdentifier` kind here? let m_c = p.open(); p.expect(Identifier); p.close(m_c, ComponentIdentifier); - while p.at(LBracket) { - p.expect(LBracket); - expression(p); - p.expect(RBracket); - } - if p.at(Assign) { + // support array component + // eg: comp[N - 1][10] + let is_array = array(p); + + // do not assign for array components + if !is_array && p.at(Assign) { p.expect(Assign); + + // TODO: support `parallel` tag + // eg: component comp = parallel NameTemplate(...){...} + + // template name let m_c = p.open(); p.expect(Identifier); p.close(m_c, TemplateName); + + // template params tuple(p); } diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index 9188176..3ab99ac 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -171,6 +171,16 @@ impl<'a> Parser<'a> { current_kind.is_assign_token() } + pub fn at_inline_assign_signal(&mut self) -> bool { + let current_kind = self.current(); + current_kind.is_inline_assign_signal() + } + + pub fn at_var_assign(&mut self) -> bool { + let current_kind = self.current(); + current_kind.is_var_assign() + } + pub fn skip(&mut self) { self.next(); } diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index aa89ac0..8a72aa8 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -382,6 +382,17 @@ impl TokenKind { ) } + pub fn is_inline_assign_signal(self) -> bool { + matches!( + self, + Self::Assign | Self::RAssignSignal | Self::RAssignConstraintSignal + ) + } + + pub fn is_var_assign(self) -> bool { + matches!(self, Self::Assign) + } + pub fn is_trivial(self) -> bool { matches!( self, From 8e92b832cc193e94bb5c35d4b3eb94a2d6b03870 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 31 Dec 2024 11:50:30 +0700 Subject: [PATCH 46/59] use list identity parser in tuple --- crates/parser/src/grammar/block.rs | 6 +++--- crates/parser/src/grammar/expression.rs | 10 ++-------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/crates/parser/src/grammar/block.rs b/crates/parser/src/grammar/block.rs index 645632d..52e4137 100644 --- a/crates/parser/src/grammar/block.rs +++ b/crates/parser/src/grammar/block.rs @@ -16,7 +16,8 @@ pub fn block(p: &mut Parser) { p.advance_with_error("Miss {"); } else { let m = p.open(); - p.eat(LCurly); + p.expect(LCurly); + let stmt_marker = p.open(); while !p.at(RCurly) && !p.eof() { let kind = p.current(); @@ -39,8 +40,7 @@ pub fn block(p: &mut Parser) { p.close(stmt_marker, StatementList); - p.eat(RCurly); - + p.expect(RCurly); p.close(m, Block); p.dec_rcurly(); diff --git a/crates/parser/src/grammar/expression.rs b/crates/parser/src/grammar/expression.rs index bfc9ab0..641e2f3 100644 --- a/crates/parser/src/grammar/expression.rs +++ b/crates/parser/src/grammar/expression.rs @@ -16,14 +16,8 @@ pub(super) fn tuple(p: &mut Parser) { let m = p.open(); p.expect(LParen); - if p.at(Identifier) { - p.expect(Identifier); - - while p.at(Comma) && !p.eof() { - p.expect(Comma); - p.expect(Identifier); - } - } + // iden1, iden2, iden3 + list_identity::parse(p); p.expect(RParen); p.close(m, Tuple); From 6f6d67881f493421a15fec8c60c907956a145bd7 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 31 Dec 2024 11:52:51 +0700 Subject: [PATCH 47/59] fix right curly count in block --- crates/parser/src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index 3ab99ac..0225bd9 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -137,7 +137,7 @@ impl<'a> Parser<'a> { } pub fn dec_rcurly(&mut self) { - self.context.r_curly_count += 1; + self.context.r_curly_count -= 1; } pub fn current(&mut self) -> TokenKind { From df3113dfff493d0663df496087ce5e31eab9a867 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 31 Dec 2024 12:38:16 +0700 Subject: [PATCH 48/59] extract function params --- crates/parser/src/grammar/expression.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/crates/parser/src/grammar/expression.rs b/crates/parser/src/grammar/expression.rs index 641e2f3..bf7d89f 100644 --- a/crates/parser/src/grammar/expression.rs +++ b/crates/parser/src/grammar/expression.rs @@ -8,6 +8,28 @@ pub(super) fn expression(p: &mut Parser) { p.close(m, Expression); } +/** + * grammar: "(param1, param2,..., paramn)" + * can be an empty () + */ +pub(super) fn function_params(p: &mut Parser) { + let m = p.open(); + p.expect(LParen); + + while !p.at(RParen) && !p.eof() { + expression(p); + if p.at(Comma) { + p.expect(Comma) + } else { + break; + } + } + + p.expect(RParen); + // TODO: what kind of it? + p.close(m, Tuple); +} + /** * grammar: "(Symbol_1, Symbol_2,..., Symbol_n)" * can be an empty tuple (for function cal: Mul()) @@ -85,7 +107,8 @@ pub fn expression_rec(p: &mut Parser, pb: u16) -> Option { // TODO: function call if p.at(LParen) { let m = p.open_before(lhs); - tuple(p); + // tuple(p); + function_params(p); lhs = p.close(m, Call); } From f68d36ad558d16be5ffc2af0479ed39b18a62e3b Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Tue, 31 Dec 2024 12:38:30 +0700 Subject: [PATCH 49/59] add declaration test --- ..._tests__declaration_happy_test_source.snap | 5 ++ crates/syntax/src/syntax.rs | 51 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 crates/syntax/src/snapshots/syntax__syntax__grammar_tests__declaration_happy_test_source.snap diff --git a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__declaration_happy_test_source.snap b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__declaration_happy_test_source.snap new file mode 100644 index 0000000..8327f7c --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__declaration_happy_test_source.snap @@ -0,0 +1,5 @@ +--- +source: crates/syntax/src/syntax.rs +expression: string_syntax +--- +"{\n var nout = nbits((2**n -1)*ops);\n signal input in[ops][n];\n signal output out[nout];\n \n var lin = 0;\n var lout = 0;\n \n var k;\n var j;\n \n var e2;\n \n e2 = 1;\n for (k=0; k> k) & 1;\n \n // Ensure out is binary\n out[k] * (out[k] - 1) === 0;\n \n lout += out[k] * e2;\n \n e2 = e2+e2;\n }\n \n // Ensure the sum;\n \n lin === lout;\n }\n }" diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index e233d7a..5f235be 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -465,4 +465,55 @@ mod grammar_tests { .collect(); insta::assert_yaml_snapshot!("statement_happy_test_statements", statements); } + + #[test] + fn declaration_happy_test() { + // [scope: block] source must start with { + let source = r#"{ + var nout = nbits((2**n -1)*ops); + signal input in[ops][n]; + signal output out[nout]; + + var lin = 0; + var lout = 0; + + var k; + var j; + + var e2; + + e2 = 1; + for (k=0; k> k) & 1; + + // Ensure out is binary + out[k] * (out[k] - 1) === 0; + + lout += out[k] * e2; + + e2 = e2+e2; + } + + // Ensure the sum; + + lin === lout; + } + }"#; + + + let syntax = syntax_node_from_source(&source, Scope::Block); + + // cast syntax node into ast node to retrieve more information + let block = AstBlock::cast(syntax).expect("Can not cast syntax node into ast block"); + + let string_syntax = block.syntax().text().to_string(); + insta::assert_yaml_snapshot!("declaration_happy_test_source", string_syntax); + } } From ccc72260875533a0f1a6b9a0fed0b780995ab31f Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Thu, 2 Jan 2025 09:31:37 +0700 Subject: [PATCH 50/59] comment statement in declaration test --- ...x__syntax__grammar_tests__declaration_happy_test_source.snap | 2 +- crates/syntax/src/syntax.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__declaration_happy_test_source.snap b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__declaration_happy_test_source.snap index 8327f7c..ef054ab 100644 --- a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__declaration_happy_test_source.snap +++ b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__declaration_happy_test_source.snap @@ -2,4 +2,4 @@ source: crates/syntax/src/syntax.rs expression: string_syntax --- -"{\n var nout = nbits((2**n -1)*ops);\n signal input in[ops][n];\n signal output out[nout];\n \n var lin = 0;\n var lout = 0;\n \n var k;\n var j;\n \n var e2;\n \n e2 = 1;\n for (k=0; k> k) & 1;\n \n // Ensure out is binary\n out[k] * (out[k] - 1) === 0;\n \n lout += out[k] * e2;\n \n e2 = e2+e2;\n }\n \n // Ensure the sum;\n \n lin === lout;\n }\n }" +"{\n var nout = nbits((2**n -1)*ops);\n signal input in[ops][n];\n signal output out[nout];\n \n var lin = 0;\n var lout = 0;\n \n var k;\n var j;\n \n var e2;\n \n e2 = 1;\n for (k=0; k> k) & 1;\n \n // Ensure out is binary\n // out[k] * (out[k] - 1) === 0;\n \n lout += out[k] * e2;\n \n e2 = e2+e2;\n }\n \n // Ensure the sum;\n \n lin === lout;\n }\n }" diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 5f235be..03008b7 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -494,7 +494,7 @@ mod grammar_tests { out[k] <-- (lin >> k) & 1; // Ensure out is binary - out[k] * (out[k] - 1) === 0; + // out[k] * (out[k] - 1) === 0; lout += out[k] * e2; From 9a17705e48c2fc085706e1e346a2631bb6f12222 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Thu, 2 Jan 2025 09:34:47 +0700 Subject: [PATCH 51/59] fix format --- crates/syntax/src/syntax.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index 03008b7..90e304e 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -506,13 +506,12 @@ mod grammar_tests { lin === lout; } }"#; - - + let syntax = syntax_node_from_source(&source, Scope::Block); // cast syntax node into ast node to retrieve more information let block = AstBlock::cast(syntax).expect("Can not cast syntax node into ast block"); - + let string_syntax = block.syntax().text().to_string(); insta::assert_yaml_snapshot!("declaration_happy_test_source", string_syntax); } From 09bb4facccb5c5468dafd7eefe39fa0998047fe5 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Thu, 2 Jan 2025 11:00:26 +0700 Subject: [PATCH 52/59] add function parse test --- crates/parser/src/input.rs | 1 - ...mar_tests__function_happy_test_source.snap | 5 ++++ crates/syntax/src/syntax.rs | 25 ++++++++++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 crates/syntax/src/snapshots/syntax__syntax__grammar_tests__function_happy_test_source.snap diff --git a/crates/parser/src/input.rs b/crates/parser/src/input.rs index 6278fd8..57e7317 100644 --- a/crates/parser/src/input.rs +++ b/crates/parser/src/input.rs @@ -137,7 +137,6 @@ mod tests { return r; }"#; test(source, "test_function"); - test(source, "test_function"); } #[test] diff --git a/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__function_happy_test_source.snap b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__function_happy_test_source.snap new file mode 100644 index 0000000..d8f21fc --- /dev/null +++ b/crates/syntax/src/snapshots/syntax__syntax__grammar_tests__function_happy_test_source.snap @@ -0,0 +1,5 @@ +--- +source: crates/syntax/src/syntax.rs +expression: string_function +--- +"function nbits(a) {\n var n = 1;\n var r = 0;\n while (n-1 Date: Mon, 6 Jan 2025 10:03:09 +0700 Subject: [PATCH 53/59] add comments --- crates/lsp/src/global_state.rs | 28 ++++++++++++++++++- crates/lsp/src/handler/goto_definition.rs | 17 ++++++++++- crates/syntax/src/abstract_syntax_tree/ast.rs | 3 ++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/crates/lsp/src/global_state.rs b/crates/lsp/src/global_state.rs index 40ecb64..9752284 100644 --- a/crates/lsp/src/global_state.rs +++ b/crates/lsp/src/global_state.rs @@ -44,9 +44,15 @@ impl From for TextDocument { } } +/// state of all (circom) source file pub struct GlobalState { + /// file id - ast from that file content pub ast_map: DashMap, + + /// file id - file content (+ end lines) pub file_map: DashMap, + + /// file id - database (template in4, function in4...) pub db: SemanticDB, } @@ -71,6 +77,7 @@ impl GlobalState { ast: &AstCircomProgram, token: &SyntaxToken, ) -> Vec { + // look up token in current file let semantic_data = self.db.semantic.get(&root.file_id).unwrap(); let mut result = lookup_definition(root, ast, semantic_data, token); @@ -78,6 +85,10 @@ impl GlobalState { return result; } + + // if can not find that token in current file, + // and if token in a component call / declaration + // continue looking up in libs let p = root.get_path(); if lookup_node_wrap_token(TokenKind::ComponentDecl, token).is_some() @@ -98,17 +109,27 @@ impl GlobalState { } } } + result } pub fn goto_definition_handler(&self, id: RequestId, params: GotoDefinitionParams) -> Response { + eprint!("-------------------"); + // path to the element we want to get definition + // TODO eg: file/line/start column..end column let uri = params.text_document_position_params.text_document.uri; - + + // abtract syntax tree for the element from that uri + // TODO eg: let ast = self.ast_map.get(&uri.to_string()).unwrap(); + // the file contains the element from that uri + // TODO eg: let file = self.file_map.get(&uri.to_string()).unwrap(); let mut locations = Vec::new(); + // extract token from ast at position (file, params position) + // TODO eg: if let Some(token) = lookup_token_at_postion(&file, &ast, params.text_document_position_params.position) { @@ -126,6 +147,11 @@ impl GlobalState { } } + /// update a file of (circom) source code + /// parse new code --> syntax tree + /// remove old data of that file in semantic database + /// add new data (circom_program_semantic) + related libs into database + /// update corresponding file-map and ast-map in global-state pub fn handle_update(&mut self, text_document: &TextDocument) -> Result<()> { let text = &text_document.text; let url = &text_document.uri.to_string(); diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 8609b4c..5a286c0 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -16,6 +16,7 @@ use syntax::syntax_node::SyntaxToken; use crate::database::{FileDB, SemanticData, TokenId}; +// find the first ancestor with given kind of a syntax token pub fn lookup_node_wrap_token(ast_type: TokenKind, token: &SyntaxToken) -> Option { let mut p = token.parent(); while let Some(t) = p { @@ -27,6 +28,7 @@ pub fn lookup_node_wrap_token(ast_type: TokenKind, token: &SyntaxToken) -> Optio None } +// return an Identifier/CircomString token at a position pub fn lookup_token_at_postion( file: &FileDB, ast: &AstCircomProgram, @@ -47,6 +49,7 @@ pub fn lookup_token_at_postion( }) } +// find all template name (in component declaration) which are used inside a template pub fn lookup_component(template: &AstTemplateDef, text: SyntaxText) -> Option { if let Some(statements) = template.statements() { for component in statements.find_children::() { @@ -60,6 +63,8 @@ pub fn lookup_component(template: &AstTemplateDef, text: SyntaxText) -> Option Vec { if let Some(include_lib) = lookup_node_wrap_token(TokenKind::IncludeKw, token) { if let Some(ast_include) = AstInclude::cast(include_lib) { @@ -86,6 +91,7 @@ pub fn lookup_definition( token: &SyntaxToken, ) -> Vec { let template_list = ast.template_list(); + // TODO: extract function list let mut res = Vec::new(); @@ -93,15 +99,19 @@ pub fn lookup_definition( return jump_to_lib(file, token); } + // signal from other template + // eg: in1, in2 from component call mul(in1, in2) let mut signal_outside = false; if let Some(component_call) = lookup_node_wrap_token(TokenKind::ComponentCall, token) { // find template called. if let Some(ast_component_call) = AstComponentCall::cast(component_call) { if let Some(signal) = ast_component_call.signal() { + // if target token is the parameter of a component call + // TODO: go to params in template!!! (failed) if signal.syntax().text() == token.text() { signal_outside = true; - // lookup template of componenet + // lookup template of component if let Some(current_template) = lookup_node_wrap_token(TokenKind::TemplateDef, token) { @@ -131,6 +141,8 @@ pub fn lookup_definition( } if !signal_outside { + // look up token in template information + // (template name, signal/variable/component in template) for template in template_list { let template_name = template.name().unwrap(); if template_name.name().unwrap().syntax().text() == token.text() { @@ -160,6 +172,9 @@ pub fn lookup_definition( res.extend(component_decl); } } + + // TODO: look up token in function information + // (function name, signal/variable/component in function) } res.into_iter() diff --git a/crates/syntax/src/abstract_syntax_tree/ast.rs b/crates/syntax/src/abstract_syntax_tree/ast.rs index 9d8c282..e105b64 100644 --- a/crates/syntax/src/abstract_syntax_tree/ast.rs +++ b/crates/syntax/src/abstract_syntax_tree/ast.rs @@ -48,6 +48,9 @@ impl AstVarDecl { ast_node!(AstComponentDecl, ComponentDecl); +// component hash = Poseidon(2); +// template --> Poseidon +// component_identifier --> hash impl AstComponentDecl { pub fn template(&self) -> Option { support::child(self.syntax()) From 0bf4056f15d5b968d97d8a9d3d28c5e85c685773 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Wed, 15 Jan 2025 22:19:01 +0700 Subject: [PATCH 54/59] comments: example in goto_definition_handler --- crates/lsp/src/global_state.rs | 82 +++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 12 deletions(-) diff --git a/crates/lsp/src/global_state.rs b/crates/lsp/src/global_state.rs index 9752284..93a8005 100644 --- a/crates/lsp/src/global_state.rs +++ b/crates/lsp/src/global_state.rs @@ -46,13 +46,13 @@ impl From for TextDocument { /// state of all (circom) source file pub struct GlobalState { - /// file id - ast from that file content + /// key: file id (from file url) - value: ast of its content (source code) pub ast_map: DashMap, - /// file id - file content (+ end lines) + /// key: file id (from file url) - value: file content (+ end lines) pub file_map: DashMap, - /// file id - database (template in4, function in4...) + /// key: file id (from file url) - value: database (template in4, function in4...) pub db: SemanticDB, } @@ -114,31 +114,89 @@ impl GlobalState { } pub fn goto_definition_handler(&self, id: RequestId, params: GotoDefinitionParams) -> Response { - eprint!("-------------------"); - // path to the element we want to get definition - // TODO eg: file/line/start column..end column + // path to the file that contains the element we want to get definition + // eg: file:///mnt/d/language-server/test-circom/program2.circom let uri = params.text_document_position_params.text_document.uri; - // abtract syntax tree for the element from that uri - // TODO eg: + // reference to the abtract syntax tree for the file from that uri + // eg: Ref { k: 0x56136e3ce100, v: 0x56136e3ce118 } + // ast.key() = "file:///mnt/d/language-server/test-circom/program2.circom" + // ast.value() = AstCircomProgram { syntax: CircomProgram@0..2707 } let ast = self.ast_map.get(&uri.to_string()).unwrap(); - // the file contains the element from that uri - // TODO eg: + + // information of the file contains the element we want to get definition + // eg: Ref { k: 0x56136e3bf5a0, v: 0x56136e3bf5b8 } + // file.key() = "file:///mnt/d/language-server/test-circom/program2.circom" + // file.value() = + // FileDB { + // file_id: FileId(17547606022754654883), + // file_path: Url { + // scheme: "file", + // cannot_be_a_base: false, + // username: "", + // password: None, + // host: None, + // port: None, + // path: "/mnt/d/language-server/test-circom/program2.circom", + // query: None, + // fragment: None + // }, + // end_line_vec: [2, 44, ..., 2701] + // } let file = self.file_map.get(&uri.to_string()).unwrap(); - + let mut locations = Vec::new(); // extract token from ast at position (file, params position) - // TODO eg: + // eg: token = Identifier@2205..2207 "e2" if let Some(token) = lookup_token_at_postion(&file, &ast, params.text_document_position_params.position) { locations = self.lookup_definition(&file, &ast, &token); + // locations of declarations of that element + // it may returns more than 1 location if exist same name declarations + // eg: + // [ + // Location { + // uri: Url { + // scheme: "file", + // cannot_be_a_base: false, + // username: "", + // password: None, + // host: None, + // port: None, + // path: "/mnt/d/language-server/test-circom/program2.circom", + // query: None, + // fragment: None + // }, + // range: Range { + // start: Position { line: 75, character: 8 }, + // end: Position { line: 75, character: 14 } + // } + // } + // ] }; let result: Option = Some(GotoDefinitionResponse::Array(locations)); let result = serde_json::to_value(result).unwrap(); + // serialize result into JSON format + // eg: + // Array [ + // Object { + // "range": Object { + // "end": Object { + // "character": Number(14), + // "line": Number(75) + // }, + // "start": Object { + // "character": Number(8), + // "line": Number(75) + // } + // }, + // "uri": String("file:///mnt/d/language-server/test-circom/program2.circom") + // } + // ] Response { id, From 13769d68be966c5fefd4f1f0ab4151d9f7b096cd Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Wed, 15 Jan 2025 23:22:15 +0700 Subject: [PATCH 55/59] go-to-defitition in function --- crates/lsp/src/database.rs | 155 +++++++++++++++++- crates/lsp/src/global_state.rs | 80 ++++----- crates/lsp/src/handler/goto_definition.rs | 56 ++++++- crates/syntax/src/abstract_syntax_tree/ast.rs | 7 + crates/syntax/src/syntax.rs | 7 +- 5 files changed, 250 insertions(+), 55 deletions(-) diff --git a/crates/lsp/src/database.rs b/crates/lsp/src/database.rs index 245d44b..e0bf3d5 100644 --- a/crates/lsp/src/database.rs +++ b/crates/lsp/src/database.rs @@ -11,8 +11,8 @@ use lsp_types::{Position, Range, Url}; use rowan::{ast::AstNode, TextSize}; use syntax::{ abstract_syntax_tree::{ - AstCircomProgram, AstComponentDecl, AstInputSignalDecl, AstOutputSignalDecl, AstSignalDecl, - AstTemplateDef, AstVarDecl, + AstCircomProgram, AstComponentDecl, AstFunctionDef, AstInputSignalDecl, + AstOutputSignalDecl, AstSignalDecl, AstTemplateDef, AstVarDecl, }, syntax_node::{SyntaxNode, SyntaxToken}, }; @@ -160,6 +160,7 @@ impl SemanticLocations { } } +// template #[derive(Debug, Clone)] pub struct TemplateDataSemantic { pub signal: SemanticLocations, @@ -177,10 +178,32 @@ impl TemplateDataSemantic { } } +// function +#[derive(Debug, Clone)] +pub struct FunctionDataSemantic { + // TODO: Functions cannot declare signals or generate constraints + pub signal: SemanticLocations, + pub variable: SemanticLocations, + pub component: SemanticLocations, +} + +impl FunctionDataSemantic { + fn new() -> Self { + Self { + signal: SemanticLocations::new(), + variable: SemanticLocations::new(), + component: SemanticLocations::new(), + } + } +} + #[derive(Debug, Clone)] pub struct SemanticData { pub template: SemanticLocations, pub template_data_semantic: HashMap, + + pub function: SemanticLocations, + pub function_data_semantic: HashMap, } pub enum TemplateDataInfo { @@ -188,9 +211,19 @@ pub enum TemplateDataInfo { Variable((Id, Range)), Component((Id, Range)), } + +pub enum FunctionDataInfo { + Signal((Id, Range)), + Variable((Id, Range)), + Component((Id, Range)), +} + pub enum SemanticInfo { Template((Id, Range)), TemplateData((Id, TemplateDataInfo)), + + Function((Id, Range)), + FunctionData((Id, FunctionDataInfo)), } #[derive(Debug, Clone)] @@ -215,6 +248,8 @@ impl SemanticDB { let semantic = self.semantic.entry(file_id).or_insert(SemanticData { template: SemanticLocations::new(), template_data_semantic: HashMap::new(), + function: SemanticLocations::new(), + function_data_semantic: HashMap::new(), }); match semantic_info { @@ -235,6 +270,23 @@ impl SemanticDB { TemplateDataInfo::Signal((id, r)) => template_semantic.signal.insert(id, r), } } + SemanticInfo::Function((id, range)) => { + semantic.function.insert(id, range); + } + SemanticInfo::FunctionData((function_id, function_data_info)) => { + let function_semantic = semantic + .function_data_semantic + .entry(function_id) + .or_insert(FunctionDataSemantic::new()); + + match function_data_info { + FunctionDataInfo::Component((id, r)) => { + function_semantic.component.insert(id, r) + } + FunctionDataInfo::Variable((id, r)) => function_semantic.variable.insert(id, r), + FunctionDataInfo::Signal((id, r)) => function_semantic.signal.insert(id, r), + } + } } } @@ -253,6 +305,17 @@ impl SemanticDB { self.template_semantic(file_db, &template); } } + + for function in abstract_syntax_tree.function_list() { + if let Some(name) = function.function_name() { + let function_id = name.syntax().token_id(); + self.insert( + file_db.file_id, + SemanticInfo::Function((function_id, file_db.range(function.syntax()))), + ); + self.function_semantic(file_db, &function); + } + } } pub fn template_semantic(&mut self, file_db: &FileDB, ast_template: &AstTemplateDef) { @@ -336,10 +399,54 @@ impl SemanticDB { } } } + + pub fn function_semantic(&mut self, file_db: &FileDB, ast_function: &AstFunctionDef) { + let function_id = ast_function.syntax().token_id(); + + if let Some(statements) = ast_function.statements() { + // function does not contains signal decalrations --> skip signals + + for var in statements.find_children::() { + if let Some(name) = var.name() { + self.insert( + file_db.file_id, + SemanticInfo::FunctionData(( + function_id, + FunctionDataInfo::Variable(( + name.syntax().token_id(), + file_db.range(var.syntax()), + )), + )), + ); + } + } + + for component in statements.find_children::() { + if let Some(component_var) = component.component_identifier() { + if let Some(name) = component_var.name() { + self.insert( + file_db.file_id, + SemanticInfo::FunctionData(( + function_id, + FunctionDataInfo::Component(( + name.syntax().token_id(), + file_db.range(component.syntax()), + )), + )), + ); + } + } + } + } + } } impl SemanticData { - pub fn lookup_signal(&self, template_id: Id, signal: &SyntaxToken) -> Option<&Vec> { + pub fn lookup_template_signal( + &self, + template_id: Id, + signal: &SyntaxToken, + ) -> Option<&Vec> { if let Some(semantic_template) = self.template_data_semantic.get(&template_id) { return semantic_template.signal.0.get(&signal.token_id()); } @@ -347,14 +454,18 @@ impl SemanticData { } // TODO: remove duplicate code here. - pub fn lookup_variable(&self, template_id: Id, variable: &SyntaxToken) -> Option<&Vec> { + pub fn lookup_template_variable( + &self, + template_id: Id, + variable: &SyntaxToken, + ) -> Option<&Vec> { if let Some(semantic_template) = self.template_data_semantic.get(&template_id) { return semantic_template.variable.0.get(&variable.token_id()); } None } - pub fn lookup_component( + pub fn lookup_template_component( &self, template_id: Id, component: &SyntaxToken, @@ -364,6 +475,40 @@ impl SemanticData { } None } + + // ------------- function + pub fn lookup_function_signal( + &self, + function_id: Id, + signal: &SyntaxToken, + ) -> Option<&Vec> { + if let Some(semantic_function) = self.function_data_semantic.get(&function_id) { + return semantic_function.signal.0.get(&signal.token_id()); + } + None + } + + pub fn lookup_function_variable( + &self, + function_id: Id, + variable: &SyntaxToken, + ) -> Option<&Vec> { + if let Some(semantic_function) = self.function_data_semantic.get(&function_id) { + return semantic_function.variable.0.get(&variable.token_id()); + } + None + } + + pub fn lookup_function_component( + &self, + function_id: Id, + component: &SyntaxToken, + ) -> Option<&Vec> { + if let Some(semantic_function) = self.function_data_semantic.get(&function_id) { + return semantic_function.component.0.get(&component.token_id()); + } + None + } } #[cfg(test)] diff --git a/crates/lsp/src/global_state.rs b/crates/lsp/src/global_state.rs index 93a8005..879f5fd 100644 --- a/crates/lsp/src/global_state.rs +++ b/crates/lsp/src/global_state.rs @@ -82,10 +82,10 @@ impl GlobalState { let mut result = lookup_definition(root, ast, semantic_data, token); if token.kind() == TokenKind::CircomString { + eprintln!("___ definition inside current file"); return result; } - // if can not find that token in current file, // and if token in a component call / declaration // continue looking up in libs @@ -117,34 +117,34 @@ impl GlobalState { // path to the file that contains the element we want to get definition // eg: file:///mnt/d/language-server/test-circom/program2.circom let uri = params.text_document_position_params.text_document.uri; - + // reference to the abtract syntax tree for the file from that uri // eg: Ref { k: 0x56136e3ce100, v: 0x56136e3ce118 } // ast.key() = "file:///mnt/d/language-server/test-circom/program2.circom" // ast.value() = AstCircomProgram { syntax: CircomProgram@0..2707 } let ast = self.ast_map.get(&uri.to_string()).unwrap(); - + // information of the file contains the element we want to get definition // eg: Ref { k: 0x56136e3bf5a0, v: 0x56136e3bf5b8 } // file.key() = "file:///mnt/d/language-server/test-circom/program2.circom" - // file.value() = - // FileDB { - // file_id: FileId(17547606022754654883), - // file_path: Url { - // scheme: "file", - // cannot_be_a_base: false, - // username: "", - // password: None, - // host: None, - // port: None, - // path: "/mnt/d/language-server/test-circom/program2.circom", - // query: None, - // fragment: None - // }, - // end_line_vec: [2, 44, ..., 2701] + // file.value() = + // FileDB { + // file_id: FileId(17547606022754654883), + // file_path: Url { + // scheme: "file", + // cannot_be_a_base: false, + // username: "", + // password: None, + // host: None, + // port: None, + // path: "/mnt/d/language-server/test-circom/program2.circom", + // query: None, + // fragment: None + // }, + // end_line_vec: [2, 44, ..., 2701] // } let file = self.file_map.get(&uri.to_string()).unwrap(); - + let mut locations = Vec::new(); // extract token from ast at position (file, params position) @@ -155,24 +155,24 @@ impl GlobalState { locations = self.lookup_definition(&file, &ast, &token); // locations of declarations of that element // it may returns more than 1 location if exist same name declarations - // eg: + // eg: // [ - // Location { - // uri: Url { - // scheme: "file", - // cannot_be_a_base: false, - // username: "", - // password: None, - // host: None, - // port: None, - // path: "/mnt/d/language-server/test-circom/program2.circom", - // query: None, - // fragment: None - // }, - // range: Range { - // start: Position { line: 75, character: 8 }, - // end: Position { line: 75, character: 14 } - // } + // Location { + // uri: Url { + // scheme: "file", + // cannot_be_a_base: false, + // username: "", + // password: None, + // host: None, + // port: None, + // path: "/mnt/d/language-server/test-circom/program2.circom", + // query: None, + // fragment: None + // }, + // range: Range { + // start: Position { line: 75, character: 8 }, + // end: Position { line: 75, character: 14 } + // } // } // ] }; @@ -186,14 +186,14 @@ impl GlobalState { // Object { // "range": Object { // "end": Object { - // "character": Number(14), + // "character": Number(14), // "line": Number(75) - // }, + // }, // "start": Object { - // "character": Number(8), + // "character": Number(8), // "line": Number(75) // } - // }, + // }, // "uri": String("file:///mnt/d/language-server/test-circom/program2.circom") // } // ] diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 5a286c0..45e1ea3 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -45,6 +45,7 @@ pub fn lookup_token_at_postion( if kind == TokenKind::CircomString { return Some(token); } + None }) } @@ -91,7 +92,7 @@ pub fn lookup_definition( token: &SyntaxToken, ) -> Vec { let template_list = ast.template_list(); - // TODO: extract function list + let function_list = ast.function_list(); let mut res = Vec::new(); @@ -99,8 +100,8 @@ pub fn lookup_definition( return jump_to_lib(file, token); } - // signal from other template - // eg: in1, in2 from component call mul(in1, in2) + // signal from other template + // eg: in1, in2 from component call `mul(in1, in2)` let mut signal_outside = false; if let Some(component_call) = lookup_node_wrap_token(TokenKind::ComponentCall, token) { @@ -141,8 +142,12 @@ pub fn lookup_definition( } if !signal_outside { - // look up token in template information + // TODO: look up token in param list of node wrap token + + // look up token in template information // (template name, signal/variable/component in template) + + eprintln!("look up in templates..."); for template in template_list { let template_name = template.name().unwrap(); if template_name.name().unwrap().syntax().text() == token.text() { @@ -160,21 +165,56 @@ pub fn lookup_definition( let template_id = template.syntax().token_id(); - if let Some(data) = semantic_data.lookup_signal(template_id, token) { + if let Some(data) = semantic_data.lookup_template_signal(template_id, token) { res.extend(data); } - if let Some(data) = semantic_data.lookup_variable(template_id, token) { + if let Some(data) = semantic_data.lookup_template_variable(template_id, token) { res.extend(data); } - if let Some(component_decl) = semantic_data.lookup_component(template_id, token) { + if let Some(component_decl) = + semantic_data.lookup_template_component(template_id, token) + { res.extend(component_decl); } } - // TODO: look up token in function information + // TODO: look up token in function information // (function name, signal/variable/component in function) + + eprintln!("look up in functions..."); + for function in function_list { + let function_name = function.function_name().unwrap(); + if function_name.syntax().text() == token.text() { + let range = file.range(function.syntax()); + res.push(range); + } + + if !function + .syntax() + .text_range() + .contains_range(token.text_range()) + { + continue; + } + + let function_id = function.syntax().token_id(); + + if let Some(data) = semantic_data.lookup_function_signal(function_id, token) { + res.extend(data); + } + + if let Some(data) = semantic_data.lookup_function_variable(function_id, token) { + res.extend(data); + } + + if let Some(component_decl) = + semantic_data.lookup_function_component(function_id, token) + { + res.extend(component_decl); + } + } } res.into_iter() diff --git a/crates/syntax/src/abstract_syntax_tree/ast.rs b/crates/syntax/src/abstract_syntax_tree/ast.rs index e105b64..2560a58 100644 --- a/crates/syntax/src/abstract_syntax_tree/ast.rs +++ b/crates/syntax/src/abstract_syntax_tree/ast.rs @@ -115,6 +115,13 @@ impl AstFunctionDef { pub fn argument_list(&self) -> Option { self.syntax().children().find_map(AstParameterList::cast) } + + pub fn statements(&self) -> Option { + if let Some(body) = self.body() { + return body.statement_list(); + } + None + } } ast_node!(AstCircomProgram, CircomProgram); diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index bd89e7b..feb149d 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -238,7 +238,9 @@ mod tests { mod grammar_tests { use crate::{ - abstract_syntax_tree::{AstBlock, AstCircomProgram, AstOutputSignalDecl, AstPragma, AstTemplateDef}, + abstract_syntax_tree::{ + AstBlock, AstCircomProgram, AstOutputSignalDecl, AstPragma, AstTemplateDef, + }, syntax::SyntaxTreeBuilder, syntax_node::CircomLanguage, }; @@ -532,7 +534,8 @@ mod grammar_tests { let syntax = syntax_node_from_source(&source, Scope::CircomProgram); // cast syntax node into ast node to retrieve more information - let ast_circom = AstCircomProgram::cast(syntax).expect("Can not cast syntax node into ast circom"); + let ast_circom = + AstCircomProgram::cast(syntax).expect("Can not cast syntax node into ast circom"); let function = &ast_circom.function_list()[0]; let string_function = function.syntax().text().to_string(); From e8da63216ddd184904c3a3396058e31cb06070ec Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Wed, 15 Jan 2025 23:49:17 +0700 Subject: [PATCH 56/59] lookup in params --- crates/lsp/src/database.rs | 60 +++++++++++++++++++ crates/lsp/src/handler/goto_definition.rs | 8 +++ crates/syntax/src/abstract_syntax_tree/ast.rs | 13 ++++ 3 files changed, 81 insertions(+) diff --git a/crates/lsp/src/database.rs b/crates/lsp/src/database.rs index e0bf3d5..b4982ef 100644 --- a/crates/lsp/src/database.rs +++ b/crates/lsp/src/database.rs @@ -163,6 +163,7 @@ impl SemanticLocations { // template #[derive(Debug, Clone)] pub struct TemplateDataSemantic { + pub param: SemanticLocations, pub signal: SemanticLocations, pub variable: SemanticLocations, pub component: SemanticLocations, @@ -171,6 +172,7 @@ pub struct TemplateDataSemantic { impl TemplateDataSemantic { fn new() -> Self { Self { + param: SemanticLocations::new(), signal: SemanticLocations::new(), variable: SemanticLocations::new(), component: SemanticLocations::new(), @@ -181,6 +183,7 @@ impl TemplateDataSemantic { // function #[derive(Debug, Clone)] pub struct FunctionDataSemantic { + pub param: SemanticLocations, // TODO: Functions cannot declare signals or generate constraints pub signal: SemanticLocations, pub variable: SemanticLocations, @@ -190,6 +193,7 @@ pub struct FunctionDataSemantic { impl FunctionDataSemantic { fn new() -> Self { Self { + param: SemanticLocations::new(), signal: SemanticLocations::new(), variable: SemanticLocations::new(), component: SemanticLocations::new(), @@ -207,12 +211,14 @@ pub struct SemanticData { } pub enum TemplateDataInfo { + Param((Id, Range)), Signal((Id, Range)), Variable((Id, Range)), Component((Id, Range)), } pub enum FunctionDataInfo { + Param((Id, Range)), Signal((Id, Range)), Variable((Id, Range)), Component((Id, Range)), @@ -268,6 +274,7 @@ impl SemanticDB { } TemplateDataInfo::Variable((id, r)) => template_semantic.variable.insert(id, r), TemplateDataInfo::Signal((id, r)) => template_semantic.signal.insert(id, r), + TemplateDataInfo::Param((id, r)) => template_semantic.param.insert(id, r), } } SemanticInfo::Function((id, range)) => { @@ -285,6 +292,7 @@ impl SemanticDB { } FunctionDataInfo::Variable((id, r)) => function_semantic.variable.insert(id, r), FunctionDataInfo::Signal((id, r)) => function_semantic.signal.insert(id, r), + FunctionDataInfo::Param((id, r)) => function_semantic.param.insert(id, r), } } } @@ -321,6 +329,21 @@ impl SemanticDB { pub fn template_semantic(&mut self, file_db: &FileDB, ast_template: &AstTemplateDef) { let template_id = ast_template.syntax().token_id(); + if let Some(params) = ast_template.parameter_list() { + for param_name in params.parameters() { + self.insert( + file_db.file_id, + SemanticInfo::TemplateData(( + template_id, + TemplateDataInfo::Param(( + param_name.syntax().token_id(), + file_db.range(param_name.syntax()), + )), + )), + ); + } + }; + if let Some(statements) = ast_template.statements() { for signal in statements.find_children::() { if let Some(name) = signal.name() { @@ -403,6 +426,21 @@ impl SemanticDB { pub fn function_semantic(&mut self, file_db: &FileDB, ast_function: &AstFunctionDef) { let function_id = ast_function.syntax().token_id(); + if let Some(params) = ast_function.parameter_list() { + for param_name in params.parameters() { + self.insert( + file_db.file_id, + SemanticInfo::FunctionData(( + function_id, + FunctionDataInfo::Param(( + param_name.syntax().token_id(), + file_db.range(param_name.syntax()), + )), + )), + ); + } + }; + if let Some(statements) = ast_function.statements() { // function does not contains signal decalrations --> skip signals @@ -442,6 +480,17 @@ impl SemanticDB { } impl SemanticData { + pub fn lookup_template_param( + &self, + template_id: Id, + signal: &SyntaxToken, + ) -> Option<&Vec> { + if let Some(semantic_template) = self.template_data_semantic.get(&template_id) { + return semantic_template.param.0.get(&signal.token_id()); + } + None + } + pub fn lookup_template_signal( &self, template_id: Id, @@ -477,6 +526,17 @@ impl SemanticData { } // ------------- function + pub fn lookup_function_param( + &self, + function_id: Id, + signal: &SyntaxToken, + ) -> Option<&Vec> { + if let Some(semantic_function) = self.function_data_semantic.get(&function_id) { + return semantic_function.param.0.get(&signal.token_id()); + } + None + } + pub fn lookup_function_signal( &self, function_id: Id, diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 45e1ea3..3b953d7 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -165,6 +165,10 @@ pub fn lookup_definition( let template_id = template.syntax().token_id(); + if let Some(data) = semantic_data.lookup_template_param(template_id, token) { + res.extend(data); + } + if let Some(data) = semantic_data.lookup_template_signal(template_id, token) { res.extend(data); } @@ -201,6 +205,10 @@ pub fn lookup_definition( let function_id = function.syntax().token_id(); + if let Some(data) = semantic_data.lookup_function_param(function_id, token) { + res.extend(data); + } + if let Some(data) = semantic_data.lookup_function_signal(function_id, token) { res.extend(data); } diff --git a/crates/syntax/src/abstract_syntax_tree/ast.rs b/crates/syntax/src/abstract_syntax_tree/ast.rs index 2560a58..2febabe 100644 --- a/crates/syntax/src/abstract_syntax_tree/ast.rs +++ b/crates/syntax/src/abstract_syntax_tree/ast.rs @@ -91,6 +91,15 @@ impl AstPragma { } ast_node!(AstParameterList, TokenKind::ParameterList); +impl AstParameterList { + pub fn parameters(&self) -> Vec { + self.syntax() + .children() + .filter_map(AstIdentifier::cast) + .collect() + } +} + ast_node!(AstIdentifier, Identifier); impl AstIdentifier { @@ -122,6 +131,10 @@ impl AstFunctionDef { } None } + + pub fn parameter_list(&self) -> Option { + self.syntax().children().find_map(AstParameterList::cast) + } } ast_node!(AstCircomProgram, CircomProgram); From ca35cc29042f2b9ae70c612bd0fc68d13bf20b2a Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Wed, 15 Jan 2025 23:58:14 +0700 Subject: [PATCH 57/59] remove lookup signal in function --- crates/lsp/src/database.rs | 15 --------------- crates/lsp/src/handler/goto_definition.rs | 4 ---- 2 files changed, 19 deletions(-) diff --git a/crates/lsp/src/database.rs b/crates/lsp/src/database.rs index b4982ef..78614f5 100644 --- a/crates/lsp/src/database.rs +++ b/crates/lsp/src/database.rs @@ -185,7 +185,6 @@ impl TemplateDataSemantic { pub struct FunctionDataSemantic { pub param: SemanticLocations, // TODO: Functions cannot declare signals or generate constraints - pub signal: SemanticLocations, pub variable: SemanticLocations, pub component: SemanticLocations, } @@ -194,7 +193,6 @@ impl FunctionDataSemantic { fn new() -> Self { Self { param: SemanticLocations::new(), - signal: SemanticLocations::new(), variable: SemanticLocations::new(), component: SemanticLocations::new(), } @@ -219,7 +217,6 @@ pub enum TemplateDataInfo { pub enum FunctionDataInfo { Param((Id, Range)), - Signal((Id, Range)), Variable((Id, Range)), Component((Id, Range)), } @@ -291,7 +288,6 @@ impl SemanticDB { function_semantic.component.insert(id, r) } FunctionDataInfo::Variable((id, r)) => function_semantic.variable.insert(id, r), - FunctionDataInfo::Signal((id, r)) => function_semantic.signal.insert(id, r), FunctionDataInfo::Param((id, r)) => function_semantic.param.insert(id, r), } } @@ -537,17 +533,6 @@ impl SemanticData { None } - pub fn lookup_function_signal( - &self, - function_id: Id, - signal: &SyntaxToken, - ) -> Option<&Vec> { - if let Some(semantic_function) = self.function_data_semantic.get(&function_id) { - return semantic_function.signal.0.get(&signal.token_id()); - } - None - } - pub fn lookup_function_variable( &self, function_id: Id, diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 3b953d7..cabba01 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -209,10 +209,6 @@ pub fn lookup_definition( res.extend(data); } - if let Some(data) = semantic_data.lookup_function_signal(function_id, token) { - res.extend(data); - } - if let Some(data) = semantic_data.lookup_function_variable(function_id, token) { res.extend(data); } From b1cc42c670cbe17c60b56551d9f3d00533fe6990 Mon Sep 17 00:00:00 2001 From: NTTVy03 Date: Sat, 22 Feb 2025 11:02:51 +0700 Subject: [PATCH 58/59] fix main component grammar --- crates/parser/src/grammar/main_component.rs | 11 +- crates/parser/src/token_kind.rs | 1 + ..._test_files__happy__statements.circom.snap | 966 +++++++++--------- 3 files changed, 493 insertions(+), 485 deletions(-) diff --git a/crates/parser/src/grammar/main_component.rs b/crates/parser/src/grammar/main_component.rs index 2fd307b..5f2606d 100644 --- a/crates/parser/src/grammar/main_component.rs +++ b/crates/parser/src/grammar/main_component.rs @@ -8,17 +8,24 @@ component main {public [signal_list]} = tempid(v1,...,vn); {public [signal_list]} is optional */ pub fn main_component(p: &mut Parser) { + let open_marker = p.open(); + + // component main p.expect(ComponentKw); p.expect(MainKw); + // {public [signal_list]} if p.at(LCurly) { p.expect(LCurly); p.expect(PublicKw); - p.expect(LBracket); list_identifier(p); - p.expect(RBracket); + p.expect(RCurly); } + // = tempid(v1,...,vn); p.expect(Assign); expression::expression(p); + p.expect(Semicolon); + + p.close(open_marker, MainComponent); } diff --git a/crates/parser/src/token_kind.rs b/crates/parser/src/token_kind.rs index ef40c54..ebba8d1 100644 --- a/crates/parser/src/token_kind.rs +++ b/crates/parser/src/token_kind.rs @@ -225,6 +225,7 @@ pub enum TokenKind { ExpressionAtom, Expression, // Complex token kind + MainComponent, Block, ParameterList, Call, diff --git a/crates/syntax/src/snapshots/syntax__syntax__tests____src__test_files__happy__statements.circom.snap b/crates/syntax/src/snapshots/syntax__syntax__tests____src__test_files__happy__statements.circom.snap index 0a952c6..5180e08 100644 --- a/crates/syntax/src/snapshots/syntax__syntax__tests____src__test_files__happy__statements.circom.snap +++ b/crates/syntax/src/snapshots/syntax__syntax__tests____src__test_files__happy__statements.circom.snap @@ -1,483 +1,483 @@ ---- -source: crates/syntax/src/syntax.rs -expression: "crate :: view_syntax :: view_ast(& syntax)" ---- - Block 0..456 -| LCurly 0..1 -| | LCurly 0..1 "{" -| EndLine 1..3 -| | EndLine 1..3 "\r\n" -| WhiteSpace 3..7 -| | WhiteSpace 3..7 " " -| CommentLine 7..22 -| | CommentLine 7..22 "// if ... else " -| EndLine 22..24 -| | EndLine 22..24 "\r\n" -| WhiteSpace 24..28 -| | WhiteSpace 24..28 " " -| StatementList 28..455 -| | IfStatement 28..128 -| | | IfKw 28..30 -| | | | IfKw 28..30 "if" -| | | LParen 30..31 -| | | | LParen 30..31 "(" -| | | Expression 31..37 -| | | | Equal 31..37 -| | | | | ExpressionAtom 31..32 -| | | | | | Identifier 31..32 -| | | | | | | Identifier 31..32 "n" -| | | | | WhiteSpace 32..33 -| | | | | | WhiteSpace 32..33 " " -| | | | | Equal 33..35 -| | | | | | Equal 33..35 "==" -| | | | | WhiteSpace 35..36 -| | | | | | WhiteSpace 35..36 " " -| | | | | ExpressionAtom 36..37 -| | | | | | Number 36..37 -| | | | | | | Number 36..37 "2" -| | | RParen 37..38 -| | | | RParen 37..38 ")" -| | | WhiteSpace 38..39 -| | | | WhiteSpace 38..39 " " -| | | Block 39..94 -| | | | LCurly 39..40 -| | | | | LCurly 39..40 "{" -| | | | EndLine 40..42 -| | | | | EndLine 40..42 "\r\n" -| | | | WhiteSpace 42..50 -| | | | | WhiteSpace 42..50 " " -| | | | StatementList 50..93 -| | | | | AssignStatement 50..59 -| | | | | | Expression 50..54 -| | | | | | | ExpressionAtom 50..53 -| | | | | | | | Identifier 50..53 -| | | | | | | | | Identifier 50..53 "aux" -| | | | | | | WhiteSpace 53..54 -| | | | | | | | WhiteSpace 53..54 " " -| | | | | | RAssignConstraintSignal 54..57 -| | | | | | | RAssignConstraintSignal 54..57 "<==" -| | | | | | WhiteSpace 57..58 -| | | | | | | WhiteSpace 57..58 " " -| | | | | | Expression 58..59 -| | | | | | | ExpressionAtom 58..59 -| | | | | | | | Number 58..59 -| | | | | | | | | Number 58..59 "2" -| | | | | Semicolon 59..60 -| | | | | | Semicolon 59..60 ";" -| | | | | EndLine 60..62 -| | | | | | EndLine 60..62 "\r\n" -| | | | | WhiteSpace 62..70 -| | | | | | WhiteSpace 62..70 " " -| | | | | AssignStatement 70..86 -| | | | | | Expression 70..74 -| | | | | | | ExpressionAtom 70..73 -| | | | | | | | Identifier 70..73 -| | | | | | | | | Identifier 70..73 "out" -| | | | | | | WhiteSpace 73..74 -| | | | | | | | WhiteSpace 73..74 " " -| | | | | | RAssignConstraintSignal 74..77 -| | | | | | | RAssignConstraintSignal 74..77 "<==" -| | | | | | WhiteSpace 77..78 -| | | | | | | WhiteSpace 77..78 " " -| | | | | | Expression 78..86 -| | | | | | | Call 78..86 -| | | | | | | | Call 78..81 -| | | | | | | | | ExpressionAtom 78..79 -| | | | | | | | | | Identifier 78..79 -| | | | | | | | | | | Identifier 78..79 "B" -| | | | | | | | | LParen 79..80 -| | | | | | | | | | LParen 79..80 "(" -| | | | | | | | | RParen 80..81 -| | | | | | | | | | RParen 80..81 ")" -| | | | | | | | LParen 81..82 -| | | | | | | | | LParen 81..82 "(" -| | | | | | | | Expression 82..85 -| | | | | | | | | ExpressionAtom 82..85 -| | | | | | | | | | Identifier 82..85 -| | | | | | | | | | | Identifier 82..85 "aux" -| | | | | | | | RParen 85..86 -| | | | | | | | | RParen 85..86 ")" -| | | | | Semicolon 86..87 -| | | | | | Semicolon 86..87 ";" -| | | | | EndLine 87..89 -| | | | | | EndLine 87..89 "\r\n" -| | | | | WhiteSpace 89..93 -| | | | | | WhiteSpace 89..93 " " -| | | | RCurly 93..94 -| | | | | RCurly 93..94 "}" -| | | WhiteSpace 94..95 -| | | | WhiteSpace 94..95 " " -| | | ElseKw 95..99 -| | | | ElseKw 95..99 "else" -| | | WhiteSpace 99..100 -| | | | WhiteSpace 99..100 " " -| | | Block 100..128 -| | | | LCurly 100..101 -| | | | | LCurly 100..101 "{" -| | | | EndLine 101..103 -| | | | | EndLine 101..103 "\r\n" -| | | | WhiteSpace 103..111 -| | | | | WhiteSpace 103..111 " " -| | | | StatementList 111..127 -| | | | | AssignStatement 111..120 -| | | | | | Expression 111..115 -| | | | | | | ExpressionAtom 111..114 -| | | | | | | | Identifier 111..114 -| | | | | | | | | Identifier 111..114 "out" -| | | | | | | WhiteSpace 114..115 -| | | | | | | | WhiteSpace 114..115 " " -| | | | | | RAssignConstraintSignal 115..118 -| | | | | | | RAssignConstraintSignal 115..118 "<==" -| | | | | | WhiteSpace 118..119 -| | | | | | | WhiteSpace 118..119 " " -| | | | | | Expression 119..120 -| | | | | | | ExpressionAtom 119..120 -| | | | | | | | Number 119..120 -| | | | | | | | | Number 119..120 "5" -| | | | | Semicolon 120..121 -| | | | | | Semicolon 120..121 ";" -| | | | | EndLine 121..123 -| | | | | | EndLine 121..123 "\r\n" -| | | | | WhiteSpace 123..127 -| | | | | | WhiteSpace 123..127 " " -| | | | RCurly 127..128 -| | | | | RCurly 127..128 "}" -| | EndLine 128..130 -| | | EndLine 128..130 "\r\n" -| | EndLine 130..132 -| | | EndLine 130..132 "\r\n" -| | WhiteSpace 132..136 -| | | WhiteSpace 132..136 " " -| | CommentLine 136..142 -| | | CommentLine 136..142 "// for" -| | EndLine 142..144 -| | | EndLine 142..144 "\r\n" -| | WhiteSpace 144..148 -| | | WhiteSpace 144..148 " " -| | ForLoop 148..218 -| | | ForKw 148..151 -| | | | ForKw 148..151 "for" -| | | LParen 151..152 -| | | | LParen 151..152 "(" -| | | VarDecl 152..161 -| | | | VarKw 152..155 -| | | | | VarKw 152..155 "var" -| | | | WhiteSpace 155..156 -| | | | | WhiteSpace 155..156 " " -| | | | ComplexIdentifier 156..158 -| | | | | Identifier 156..157 -| | | | | | Identifier 156..157 "i" -| | | | | WhiteSpace 157..158 -| | | | | | WhiteSpace 157..158 " " -| | | | Assign 158..159 -| | | | | Assign 158..159 "=" -| | | | WhiteSpace 159..160 -| | | | | WhiteSpace 159..160 " " -| | | | Expression 160..161 -| | | | | ExpressionAtom 160..161 -| | | | | | Number 160..161 -| | | | | | | Number 160..161 "0" -| | | Semicolon 161..162 -| | | | Semicolon 161..162 ";" -| | | WhiteSpace 162..163 -| | | | WhiteSpace 162..163 " " -| | | Expression 163..170 -| | | | LessThan 163..170 -| | | | | ExpressionAtom 163..164 -| | | | | | Identifier 163..164 -| | | | | | | Identifier 163..164 "i" -| | | | | WhiteSpace 164..165 -| | | | | | WhiteSpace 164..165 " " -| | | | | LessThan 165..166 -| | | | | | LessThan 165..166 "<" -| | | | | WhiteSpace 166..167 -| | | | | | WhiteSpace 166..167 " " -| | | | | Sub 167..170 -| | | | | | ExpressionAtom 167..168 -| | | | | | | Identifier 167..168 -| | | | | | | | Identifier 167..168 "N" -| | | | | | Sub 168..169 -| | | | | | | Sub 168..169 "-" -| | | | | | ExpressionAtom 169..170 -| | | | | | | Number 169..170 -| | | | | | | | Number 169..170 "1" -| | | Semicolon 170..171 -| | | | Semicolon 170..171 ";" -| | | WhiteSpace 171..172 -| | | | WhiteSpace 171..172 " " -| | | AssignStatement 172..175 -| | | | Expression 172..175 -| | | | | UnitInc 172..175 -| | | | | | ExpressionAtom 172..173 -| | | | | | | Identifier 172..173 -| | | | | | | | Identifier 172..173 "i" -| | | | | | UnitInc 173..175 -| | | | | | | UnitInc 173..175 "++" -| | | RParen 175..176 -| | | | RParen 175..176 ")" -| | | Block 176..218 -| | | | LCurly 176..177 -| | | | | LCurly 176..177 "{" -| | | | EndLine 177..179 -| | | | | EndLine 177..179 "\r\n" -| | | | WhiteSpace 179..187 -| | | | | WhiteSpace 179..187 " " -| | | | StatementList 187..217 -| | | | | AssignStatement 187..210 -| | | | | | Expression 187..195 -| | | | | | | ArrayQuery 187..194 -| | | | | | | | ExpressionAtom 187..191 -| | | | | | | | | Identifier 187..191 -| | | | | | | | | | Identifier 187..191 "comp" -| | | | | | | | LBracket 191..192 -| | | | | | | | | LBracket 191..192 "[" -| | | | | | | | Expression 192..193 -| | | | | | | | | ExpressionAtom 192..193 -| | | | | | | | | | Identifier 192..193 -| | | | | | | | | | | Identifier 192..193 "i" -| | | | | | | | RBracket 193..194 -| | | | | | | | | RBracket 193..194 "]" -| | | | | | | WhiteSpace 194..195 -| | | | | | | | WhiteSpace 194..195 " " -| | | | | | Assign 195..196 -| | | | | | | Assign 195..196 "=" -| | | | | | WhiteSpace 196..197 -| | | | | | | WhiteSpace 196..197 " " -| | | | | | Expression 197..210 -| | | | | | | Call 197..210 -| | | | | | | | ExpressionAtom 197..208 -| | | | | | | | | Identifier 197..208 -| | | | | | | | | | Identifier 197..208 "Multiplier2" -| | | | | | | | LParen 208..209 -| | | | | | | | | LParen 208..209 "(" -| | | | | | | | RParen 209..210 -| | | | | | | | | RParen 209..210 ")" -| | | | | Semicolon 210..211 -| | | | | | Semicolon 210..211 ";" -| | | | | EndLine 211..213 -| | | | | | EndLine 211..213 "\r\n" -| | | | | WhiteSpace 213..217 -| | | | | | WhiteSpace 213..217 " " -| | | | RCurly 217..218 -| | | | | RCurly 217..218 "}" -| | EndLine 218..220 -| | | EndLine 218..220 "\r\n" -| | EndLine 220..222 -| | | EndLine 220..222 "\r\n" -| | WhiteSpace 222..226 -| | | WhiteSpace 222..226 " " -| | CommentLine 226..234 -| | | CommentLine 226..234 "// while" -| | EndLine 234..236 -| | | EndLine 234..236 "\r\n" -| | WhiteSpace 236..240 -| | | WhiteSpace 236..240 " " -| | WhileLoop 240..293 -| | | WhileKw 240..245 -| | | | WhileKw 240..245 "while" -| | | WhiteSpace 245..246 -| | | | WhiteSpace 245..246 " " -| | | LParen 246..247 -| | | | LParen 246..247 "(" -| | | Expression 247..252 -| | | | LessThan 247..252 -| | | | | Sub 247..250 -| | | | | | ExpressionAtom 247..248 -| | | | | | | Identifier 247..248 -| | | | | | | | Identifier 247..248 "n" -| | | | | | Sub 248..249 -| | | | | | | Sub 248..249 "-" -| | | | | | ExpressionAtom 249..250 -| | | | | | | Number 249..250 -| | | | | | | | Number 249..250 "1" -| | | | | LessThan 250..251 -| | | | | | LessThan 250..251 "<" -| | | | | ExpressionAtom 251..252 -| | | | | | Identifier 251..252 -| | | | | | | Identifier 251..252 "a" -| | | RParen 252..253 -| | | | RParen 252..253 ")" -| | | WhiteSpace 253..254 -| | | | WhiteSpace 253..254 " " -| | | Block 254..293 -| | | | LCurly 254..255 -| | | | | LCurly 254..255 "{" -| | | | EndLine 255..257 -| | | | | EndLine 255..257 "\r\n" -| | | | WhiteSpace 257..265 -| | | | | WhiteSpace 257..265 " " -| | | | StatementList 265..292 -| | | | | AssignStatement 265..268 -| | | | | | Expression 265..268 -| | | | | | | UnitInc 265..268 -| | | | | | | | ExpressionAtom 265..266 -| | | | | | | | | Identifier 265..266 -| | | | | | | | | | Identifier 265..266 "r" -| | | | | | | | UnitInc 266..268 -| | | | | | | | | UnitInc 266..268 "++" -| | | | | Semicolon 268..269 -| | | | | | Semicolon 268..269 ";" -| | | | | EndLine 269..271 -| | | | | | EndLine 269..271 "\r\n" -| | | | | WhiteSpace 271..279 -| | | | | | WhiteSpace 271..279 " " -| | | | | AssignStatement 279..285 -| | | | | | Expression 279..281 -| | | | | | | ExpressionAtom 279..280 -| | | | | | | | Identifier 279..280 -| | | | | | | | | Identifier 279..280 "n" -| | | | | | | WhiteSpace 280..281 -| | | | | | | | WhiteSpace 280..281 " " -| | | | | | MulAssign 281..283 -| | | | | | | MulAssign 281..283 "*=" -| | | | | | WhiteSpace 283..284 -| | | | | | | WhiteSpace 283..284 " " -| | | | | | Expression 284..285 -| | | | | | | ExpressionAtom 284..285 -| | | | | | | | Number 284..285 -| | | | | | | | | Number 284..285 "2" -| | | | | Semicolon 285..286 -| | | | | | Semicolon 285..286 ";" -| | | | | EndLine 286..288 -| | | | | | EndLine 286..288 "\r\n" -| | | | | WhiteSpace 288..292 -| | | | | | WhiteSpace 288..292 " " -| | | | RCurly 292..293 -| | | | | RCurly 292..293 "}" -| | EndLine 293..295 -| | | EndLine 293..295 "\r\n" -| | EndLine 295..297 -| | | EndLine 295..297 "\r\n" -| | WhiteSpace 297..301 -| | | WhiteSpace 297..301 " " -| | CommentLine 301..310 -| | | CommentLine 301..310 "// return" -| | EndLine 310..312 -| | | EndLine 310..312 "\r\n" -| | WhiteSpace 312..316 -| | | WhiteSpace 312..316 " " -| | ReturnStatement 316..324 -| | | ReturnKw 316..322 -| | | | ReturnKw 316..322 "return" -| | | WhiteSpace 322..323 -| | | | WhiteSpace 322..323 " " -| | | Expression 323..324 -| | | | ExpressionAtom 323..324 -| | | | | Identifier 323..324 -| | | | | | Identifier 323..324 "r" -| | Semicolon 324..325 -| | | Semicolon 324..325 ";" -| | EndLine 325..327 -| | | EndLine 325..327 "\r\n" -| | EndLine 327..329 -| | | EndLine 327..329 "\r\n" -| | WhiteSpace 329..333 -| | | WhiteSpace 329..333 " " -| | CommentLine 333..339 -| | | CommentLine 333..339 "// log" -| | EndLine 339..341 -| | | EndLine 339..341 "\r\n" -| | WhiteSpace 341..345 -| | | WhiteSpace 341..345 " " -| | LogStatement 345..366 -| | | LogKw 345..348 -| | | | LogKw 345..348 "log" -| | | LParen 348..349 -| | | | LParen 348..349 "(" -| | | CircomString 349..355 -| | | | CircomString 349..355 "\"hash\"" -| | | Comma 355..356 -| | | | Comma 355..356 "," -| | | WhiteSpace 356..357 -| | | | WhiteSpace 356..357 " " -| | | Expression 357..365 -| | | | ComponentCall 357..365 -| | | | | ExpressionAtom 357..361 -| | | | | | Identifier 357..361 -| | | | | | | Identifier 357..361 "hash" -| | | | | Dot 361..362 -| | | | | | Dot 361..362 "." -| | | | | Identifier 362..365 -| | | | | | Identifier 362..365 "out" -| | | RParen 365..366 -| | | | RParen 365..366 ")" -| | Semicolon 366..367 -| | | Semicolon 366..367 ";" -| | EndLine 367..369 -| | | EndLine 367..369 "\r\n" -| | EndLine 369..371 -| | | EndLine 369..371 "\r\n" -| | WhiteSpace 371..375 -| | | WhiteSpace 371..375 " " -| | CommentLine 375..384 -| | | CommentLine 375..384 "// assert" -| | EndLine 384..386 -| | | EndLine 384..386 "\r\n" -| | WhiteSpace 386..390 -| | | WhiteSpace 386..390 " " -| | AssertStatement 390..403 -| | | AssertKw 390..396 -| | | | AssertKw 390..396 "assert" -| | | LParen 396..397 -| | | | LParen 396..397 "(" -| | | Expression 397..402 -| | | | GreaterThan 397..402 -| | | | | ExpressionAtom 397..398 -| | | | | | Identifier 397..398 -| | | | | | | Identifier 397..398 "a" -| | | | | WhiteSpace 398..399 -| | | | | | WhiteSpace 398..399 " " -| | | | | GreaterThan 399..400 -| | | | | | GreaterThan 399..400 ">" -| | | | | WhiteSpace 400..401 -| | | | | | WhiteSpace 400..401 " " -| | | | | ExpressionAtom 401..402 -| | | | | | Number 401..402 -| | | | | | | Number 401..402 "2" -| | | RParen 402..403 -| | | | RParen 402..403 ")" -| | Semicolon 403..404 -| | | Semicolon 403..404 ";" -| | EndLine 404..406 -| | | EndLine 404..406 "\r\n" -| | EndLine 406..408 -| | | EndLine 406..408 "\r\n" -| | WhiteSpace 408..412 -| | | WhiteSpace 408..412 " " -| | CommentLine 412..435 -| | | CommentLine 412..435 "// assignment statement" -| | EndLine 435..437 -| | | EndLine 435..437 "\r\n" -| | WhiteSpace 437..441 -| | | WhiteSpace 437..441 " " -| | AssignStatement 441..452 -| | | Expression 441..443 -| | | | ExpressionAtom 441..442 -| | | | | Identifier 441..442 -| | | | | | Identifier 441..442 "c" -| | | | WhiteSpace 442..443 -| | | | | WhiteSpace 442..443 " " -| | | RAssignConstraintSignal 443..446 -| | | | RAssignConstraintSignal 443..446 "<==" -| | | WhiteSpace 446..447 -| | | | WhiteSpace 446..447 " " -| | | Expression 447..452 -| | | | Mul 447..452 -| | | | | ExpressionAtom 447..448 -| | | | | | Identifier 447..448 -| | | | | | | Identifier 447..448 "a" -| | | | | WhiteSpace 448..449 -| | | | | | WhiteSpace 448..449 " " -| | | | | Mul 449..450 -| | | | | | Mul 449..450 "*" -| | | | | WhiteSpace 450..451 -| | | | | | WhiteSpace 450..451 " " -| | | | | ExpressionAtom 451..452 -| | | | | | Identifier 451..452 -| | | | | | | Identifier 451..452 "b" -| | Semicolon 452..453 -| | | Semicolon 452..453 ";" -| | EndLine 453..455 -| | | EndLine 453..455 "\r\n" -| RCurly 455..456 -| | RCurly 455..456 "}" +--- +source: crates/syntax/src/syntax.rs +expression: "crate :: view_syntax :: view_ast(& syntax)" +--- + Block 0..456 +| LCurly 0..1 +| | LCurly 0..1 "{" +| EndLine 1..3 +| | EndLine 1..3 "\r\n" +| WhiteSpace 3..7 +| | WhiteSpace 3..7 " " +| CommentLine 7..22 +| | CommentLine 7..22 "// if ... else " +| EndLine 22..24 +| | EndLine 22..24 "\r\n" +| WhiteSpace 24..28 +| | WhiteSpace 24..28 " " +| StatementList 28..455 +| | IfStatement 28..128 +| | | IfKw 28..30 +| | | | IfKw 28..30 "if" +| | | LParen 30..31 +| | | | LParen 30..31 "(" +| | | Expression 31..37 +| | | | Equal 31..37 +| | | | | ExpressionAtom 31..32 +| | | | | | Identifier 31..32 +| | | | | | | Identifier 31..32 "n" +| | | | | WhiteSpace 32..33 +| | | | | | WhiteSpace 32..33 " " +| | | | | Equal 33..35 +| | | | | | Equal 33..35 "==" +| | | | | WhiteSpace 35..36 +| | | | | | WhiteSpace 35..36 " " +| | | | | ExpressionAtom 36..37 +| | | | | | Number 36..37 +| | | | | | | Number 36..37 "2" +| | | RParen 37..38 +| | | | RParen 37..38 ")" +| | | WhiteSpace 38..39 +| | | | WhiteSpace 38..39 " " +| | | Block 39..94 +| | | | LCurly 39..40 +| | | | | LCurly 39..40 "{" +| | | | EndLine 40..42 +| | | | | EndLine 40..42 "\r\n" +| | | | WhiteSpace 42..50 +| | | | | WhiteSpace 42..50 " " +| | | | StatementList 50..93 +| | | | | AssignStatement 50..59 +| | | | | | Expression 50..54 +| | | | | | | ExpressionAtom 50..53 +| | | | | | | | Identifier 50..53 +| | | | | | | | | Identifier 50..53 "aux" +| | | | | | | WhiteSpace 53..54 +| | | | | | | | WhiteSpace 53..54 " " +| | | | | | RAssignConstraintSignal 54..57 +| | | | | | | RAssignConstraintSignal 54..57 "<==" +| | | | | | WhiteSpace 57..58 +| | | | | | | WhiteSpace 57..58 " " +| | | | | | Expression 58..59 +| | | | | | | ExpressionAtom 58..59 +| | | | | | | | Number 58..59 +| | | | | | | | | Number 58..59 "2" +| | | | | Semicolon 59..60 +| | | | | | Semicolon 59..60 ";" +| | | | | EndLine 60..62 +| | | | | | EndLine 60..62 "\r\n" +| | | | | WhiteSpace 62..70 +| | | | | | WhiteSpace 62..70 " " +| | | | | AssignStatement 70..86 +| | | | | | Expression 70..74 +| | | | | | | ExpressionAtom 70..73 +| | | | | | | | Identifier 70..73 +| | | | | | | | | Identifier 70..73 "out" +| | | | | | | WhiteSpace 73..74 +| | | | | | | | WhiteSpace 73..74 " " +| | | | | | RAssignConstraintSignal 74..77 +| | | | | | | RAssignConstraintSignal 74..77 "<==" +| | | | | | WhiteSpace 77..78 +| | | | | | | WhiteSpace 77..78 " " +| | | | | | Expression 78..86 +| | | | | | | Call 78..86 +| | | | | | | | Call 78..81 +| | | | | | | | | ExpressionAtom 78..79 +| | | | | | | | | | Identifier 78..79 +| | | | | | | | | | | Identifier 78..79 "B" +| | | | | | | | | LParen 79..80 +| | | | | | | | | | LParen 79..80 "(" +| | | | | | | | | RParen 80..81 +| | | | | | | | | | RParen 80..81 ")" +| | | | | | | | LParen 81..82 +| | | | | | | | | LParen 81..82 "(" +| | | | | | | | Expression 82..85 +| | | | | | | | | ExpressionAtom 82..85 +| | | | | | | | | | Identifier 82..85 +| | | | | | | | | | | Identifier 82..85 "aux" +| | | | | | | | RParen 85..86 +| | | | | | | | | RParen 85..86 ")" +| | | | | Semicolon 86..87 +| | | | | | Semicolon 86..87 ";" +| | | | | EndLine 87..89 +| | | | | | EndLine 87..89 "\r\n" +| | | | | WhiteSpace 89..93 +| | | | | | WhiteSpace 89..93 " " +| | | | RCurly 93..94 +| | | | | RCurly 93..94 "}" +| | | WhiteSpace 94..95 +| | | | WhiteSpace 94..95 " " +| | | ElseKw 95..99 +| | | | ElseKw 95..99 "else" +| | | WhiteSpace 99..100 +| | | | WhiteSpace 99..100 " " +| | | Block 100..128 +| | | | LCurly 100..101 +| | | | | LCurly 100..101 "{" +| | | | EndLine 101..103 +| | | | | EndLine 101..103 "\r\n" +| | | | WhiteSpace 103..111 +| | | | | WhiteSpace 103..111 " " +| | | | StatementList 111..127 +| | | | | AssignStatement 111..120 +| | | | | | Expression 111..115 +| | | | | | | ExpressionAtom 111..114 +| | | | | | | | Identifier 111..114 +| | | | | | | | | Identifier 111..114 "out" +| | | | | | | WhiteSpace 114..115 +| | | | | | | | WhiteSpace 114..115 " " +| | | | | | RAssignConstraintSignal 115..118 +| | | | | | | RAssignConstraintSignal 115..118 "<==" +| | | | | | WhiteSpace 118..119 +| | | | | | | WhiteSpace 118..119 " " +| | | | | | Expression 119..120 +| | | | | | | ExpressionAtom 119..120 +| | | | | | | | Number 119..120 +| | | | | | | | | Number 119..120 "5" +| | | | | Semicolon 120..121 +| | | | | | Semicolon 120..121 ";" +| | | | | EndLine 121..123 +| | | | | | EndLine 121..123 "\r\n" +| | | | | WhiteSpace 123..127 +| | | | | | WhiteSpace 123..127 " " +| | | | RCurly 127..128 +| | | | | RCurly 127..128 "}" +| | EndLine 128..130 +| | | EndLine 128..130 "\r\n" +| | EndLine 130..132 +| | | EndLine 130..132 "\r\n" +| | WhiteSpace 132..136 +| | | WhiteSpace 132..136 " " +| | CommentLine 136..142 +| | | CommentLine 136..142 "// for" +| | EndLine 142..144 +| | | EndLine 142..144 "\r\n" +| | WhiteSpace 144..148 +| | | WhiteSpace 144..148 " " +| | ForLoop 148..218 +| | | ForKw 148..151 +| | | | ForKw 148..151 "for" +| | | LParen 151..152 +| | | | LParen 151..152 "(" +| | | VarDecl 152..161 +| | | | VarKw 152..155 +| | | | | VarKw 152..155 "var" +| | | | WhiteSpace 155..156 +| | | | | WhiteSpace 155..156 " " +| | | | ComplexIdentifier 156..158 +| | | | | Identifier 156..157 +| | | | | | Identifier 156..157 "i" +| | | | | WhiteSpace 157..158 +| | | | | | WhiteSpace 157..158 " " +| | | | Assign 158..159 +| | | | | Assign 158..159 "=" +| | | | WhiteSpace 159..160 +| | | | | WhiteSpace 159..160 " " +| | | | Expression 160..161 +| | | | | ExpressionAtom 160..161 +| | | | | | Number 160..161 +| | | | | | | Number 160..161 "0" +| | | Semicolon 161..162 +| | | | Semicolon 161..162 ";" +| | | WhiteSpace 162..163 +| | | | WhiteSpace 162..163 " " +| | | Expression 163..170 +| | | | LessThan 163..170 +| | | | | ExpressionAtom 163..164 +| | | | | | Identifier 163..164 +| | | | | | | Identifier 163..164 "i" +| | | | | WhiteSpace 164..165 +| | | | | | WhiteSpace 164..165 " " +| | | | | LessThan 165..166 +| | | | | | LessThan 165..166 "<" +| | | | | WhiteSpace 166..167 +| | | | | | WhiteSpace 166..167 " " +| | | | | Sub 167..170 +| | | | | | ExpressionAtom 167..168 +| | | | | | | Identifier 167..168 +| | | | | | | | Identifier 167..168 "N" +| | | | | | Sub 168..169 +| | | | | | | Sub 168..169 "-" +| | | | | | ExpressionAtom 169..170 +| | | | | | | Number 169..170 +| | | | | | | | Number 169..170 "1" +| | | Semicolon 170..171 +| | | | Semicolon 170..171 ";" +| | | WhiteSpace 171..172 +| | | | WhiteSpace 171..172 " " +| | | AssignStatement 172..175 +| | | | Expression 172..175 +| | | | | UnitInc 172..175 +| | | | | | ExpressionAtom 172..173 +| | | | | | | Identifier 172..173 +| | | | | | | | Identifier 172..173 "i" +| | | | | | UnitInc 173..175 +| | | | | | | UnitInc 173..175 "++" +| | | RParen 175..176 +| | | | RParen 175..176 ")" +| | | Block 176..218 +| | | | LCurly 176..177 +| | | | | LCurly 176..177 "{" +| | | | EndLine 177..179 +| | | | | EndLine 177..179 "\r\n" +| | | | WhiteSpace 179..187 +| | | | | WhiteSpace 179..187 " " +| | | | StatementList 187..217 +| | | | | AssignStatement 187..210 +| | | | | | Expression 187..195 +| | | | | | | ArrayQuery 187..194 +| | | | | | | | ExpressionAtom 187..191 +| | | | | | | | | Identifier 187..191 +| | | | | | | | | | Identifier 187..191 "comp" +| | | | | | | | LBracket 191..192 +| | | | | | | | | LBracket 191..192 "[" +| | | | | | | | Expression 192..193 +| | | | | | | | | ExpressionAtom 192..193 +| | | | | | | | | | Identifier 192..193 +| | | | | | | | | | | Identifier 192..193 "i" +| | | | | | | | RBracket 193..194 +| | | | | | | | | RBracket 193..194 "]" +| | | | | | | WhiteSpace 194..195 +| | | | | | | | WhiteSpace 194..195 " " +| | | | | | Assign 195..196 +| | | | | | | Assign 195..196 "=" +| | | | | | WhiteSpace 196..197 +| | | | | | | WhiteSpace 196..197 " " +| | | | | | Expression 197..210 +| | | | | | | Call 197..210 +| | | | | | | | ExpressionAtom 197..208 +| | | | | | | | | Identifier 197..208 +| | | | | | | | | | Identifier 197..208 "Multiplier2" +| | | | | | | | LParen 208..209 +| | | | | | | | | LParen 208..209 "(" +| | | | | | | | RParen 209..210 +| | | | | | | | | RParen 209..210 ")" +| | | | | Semicolon 210..211 +| | | | | | Semicolon 210..211 ";" +| | | | | EndLine 211..213 +| | | | | | EndLine 211..213 "\r\n" +| | | | | WhiteSpace 213..217 +| | | | | | WhiteSpace 213..217 " " +| | | | RCurly 217..218 +| | | | | RCurly 217..218 "}" +| | EndLine 218..220 +| | | EndLine 218..220 "\r\n" +| | EndLine 220..222 +| | | EndLine 220..222 "\r\n" +| | WhiteSpace 222..226 +| | | WhiteSpace 222..226 " " +| | CommentLine 226..234 +| | | CommentLine 226..234 "// while" +| | EndLine 234..236 +| | | EndLine 234..236 "\r\n" +| | WhiteSpace 236..240 +| | | WhiteSpace 236..240 " " +| | WhileLoop 240..293 +| | | WhileKw 240..245 +| | | | WhileKw 240..245 "while" +| | | WhiteSpace 245..246 +| | | | WhiteSpace 245..246 " " +| | | LParen 246..247 +| | | | LParen 246..247 "(" +| | | Expression 247..252 +| | | | LessThan 247..252 +| | | | | Sub 247..250 +| | | | | | ExpressionAtom 247..248 +| | | | | | | Identifier 247..248 +| | | | | | | | Identifier 247..248 "n" +| | | | | | Sub 248..249 +| | | | | | | Sub 248..249 "-" +| | | | | | ExpressionAtom 249..250 +| | | | | | | Number 249..250 +| | | | | | | | Number 249..250 "1" +| | | | | LessThan 250..251 +| | | | | | LessThan 250..251 "<" +| | | | | ExpressionAtom 251..252 +| | | | | | Identifier 251..252 +| | | | | | | Identifier 251..252 "a" +| | | RParen 252..253 +| | | | RParen 252..253 ")" +| | | WhiteSpace 253..254 +| | | | WhiteSpace 253..254 " " +| | | Block 254..293 +| | | | LCurly 254..255 +| | | | | LCurly 254..255 "{" +| | | | EndLine 255..257 +| | | | | EndLine 255..257 "\r\n" +| | | | WhiteSpace 257..265 +| | | | | WhiteSpace 257..265 " " +| | | | StatementList 265..292 +| | | | | AssignStatement 265..268 +| | | | | | Expression 265..268 +| | | | | | | UnitInc 265..268 +| | | | | | | | ExpressionAtom 265..266 +| | | | | | | | | Identifier 265..266 +| | | | | | | | | | Identifier 265..266 "r" +| | | | | | | | UnitInc 266..268 +| | | | | | | | | UnitInc 266..268 "++" +| | | | | Semicolon 268..269 +| | | | | | Semicolon 268..269 ";" +| | | | | EndLine 269..271 +| | | | | | EndLine 269..271 "\r\n" +| | | | | WhiteSpace 271..279 +| | | | | | WhiteSpace 271..279 " " +| | | | | AssignStatement 279..285 +| | | | | | Expression 279..281 +| | | | | | | ExpressionAtom 279..280 +| | | | | | | | Identifier 279..280 +| | | | | | | | | Identifier 279..280 "n" +| | | | | | | WhiteSpace 280..281 +| | | | | | | | WhiteSpace 280..281 " " +| | | | | | MulAssign 281..283 +| | | | | | | MulAssign 281..283 "*=" +| | | | | | WhiteSpace 283..284 +| | | | | | | WhiteSpace 283..284 " " +| | | | | | Expression 284..285 +| | | | | | | ExpressionAtom 284..285 +| | | | | | | | Number 284..285 +| | | | | | | | | Number 284..285 "2" +| | | | | Semicolon 285..286 +| | | | | | Semicolon 285..286 ";" +| | | | | EndLine 286..288 +| | | | | | EndLine 286..288 "\r\n" +| | | | | WhiteSpace 288..292 +| | | | | | WhiteSpace 288..292 " " +| | | | RCurly 292..293 +| | | | | RCurly 292..293 "}" +| | EndLine 293..295 +| | | EndLine 293..295 "\r\n" +| | EndLine 295..297 +| | | EndLine 295..297 "\r\n" +| | WhiteSpace 297..301 +| | | WhiteSpace 297..301 " " +| | CommentLine 301..310 +| | | CommentLine 301..310 "// return" +| | EndLine 310..312 +| | | EndLine 310..312 "\r\n" +| | WhiteSpace 312..316 +| | | WhiteSpace 312..316 " " +| | ReturnStatement 316..324 +| | | ReturnKw 316..322 +| | | | ReturnKw 316..322 "return" +| | | WhiteSpace 322..323 +| | | | WhiteSpace 322..323 " " +| | | Expression 323..324 +| | | | ExpressionAtom 323..324 +| | | | | Identifier 323..324 +| | | | | | Identifier 323..324 "r" +| | Semicolon 324..325 +| | | Semicolon 324..325 ";" +| | EndLine 325..327 +| | | EndLine 325..327 "\r\n" +| | EndLine 327..329 +| | | EndLine 327..329 "\r\n" +| | WhiteSpace 329..333 +| | | WhiteSpace 329..333 " " +| | CommentLine 333..339 +| | | CommentLine 333..339 "// log" +| | EndLine 339..341 +| | | EndLine 339..341 "\r\n" +| | WhiteSpace 341..345 +| | | WhiteSpace 341..345 " " +| | LogStatement 345..366 +| | | LogKw 345..348 +| | | | LogKw 345..348 "log" +| | | LParen 348..349 +| | | | LParen 348..349 "(" +| | | CircomString 349..355 +| | | | CircomString 349..355 "\"hash\"" +| | | Comma 355..356 +| | | | Comma 355..356 "," +| | | WhiteSpace 356..357 +| | | | WhiteSpace 356..357 " " +| | | Expression 357..365 +| | | | ComponentCall 357..365 +| | | | | ExpressionAtom 357..361 +| | | | | | Identifier 357..361 +| | | | | | | Identifier 357..361 "hash" +| | | | | Dot 361..362 +| | | | | | Dot 361..362 "." +| | | | | Identifier 362..365 +| | | | | | Identifier 362..365 "out" +| | | RParen 365..366 +| | | | RParen 365..366 ")" +| | Semicolon 366..367 +| | | Semicolon 366..367 ";" +| | EndLine 367..369 +| | | EndLine 367..369 "\r\n" +| | EndLine 369..371 +| | | EndLine 369..371 "\r\n" +| | WhiteSpace 371..375 +| | | WhiteSpace 371..375 " " +| | CommentLine 375..384 +| | | CommentLine 375..384 "// assert" +| | EndLine 384..386 +| | | EndLine 384..386 "\r\n" +| | WhiteSpace 386..390 +| | | WhiteSpace 386..390 " " +| | AssertStatement 390..403 +| | | AssertKw 390..396 +| | | | AssertKw 390..396 "assert" +| | | LParen 396..397 +| | | | LParen 396..397 "(" +| | | Expression 397..402 +| | | | GreaterThan 397..402 +| | | | | ExpressionAtom 397..398 +| | | | | | Identifier 397..398 +| | | | | | | Identifier 397..398 "a" +| | | | | WhiteSpace 398..399 +| | | | | | WhiteSpace 398..399 " " +| | | | | GreaterThan 399..400 +| | | | | | GreaterThan 399..400 ">" +| | | | | WhiteSpace 400..401 +| | | | | | WhiteSpace 400..401 " " +| | | | | ExpressionAtom 401..402 +| | | | | | Number 401..402 +| | | | | | | Number 401..402 "2" +| | | RParen 402..403 +| | | | RParen 402..403 ")" +| | Semicolon 403..404 +| | | Semicolon 403..404 ";" +| | EndLine 404..406 +| | | EndLine 404..406 "\r\n" +| | EndLine 406..408 +| | | EndLine 406..408 "\r\n" +| | WhiteSpace 408..412 +| | | WhiteSpace 408..412 " " +| | CommentLine 412..435 +| | | CommentLine 412..435 "// assignment statement" +| | EndLine 435..437 +| | | EndLine 435..437 "\r\n" +| | WhiteSpace 437..441 +| | | WhiteSpace 437..441 " " +| | AssignStatement 441..452 +| | | Expression 441..443 +| | | | ExpressionAtom 441..442 +| | | | | Identifier 441..442 +| | | | | | Identifier 441..442 "c" +| | | | WhiteSpace 442..443 +| | | | | WhiteSpace 442..443 " " +| | | RAssignConstraintSignal 443..446 +| | | | RAssignConstraintSignal 443..446 "<==" +| | | WhiteSpace 446..447 +| | | | WhiteSpace 446..447 " " +| | | Expression 447..452 +| | | | Mul 447..452 +| | | | | ExpressionAtom 447..448 +| | | | | | Identifier 447..448 +| | | | | | | Identifier 447..448 "a" +| | | | | WhiteSpace 448..449 +| | | | | | WhiteSpace 448..449 " " +| | | | | Mul 449..450 +| | | | | | Mul 449..450 "*" +| | | | | WhiteSpace 450..451 +| | | | | | WhiteSpace 450..451 " " +| | | | | ExpressionAtom 451..452 +| | | | | | Identifier 451..452 +| | | | | | | Identifier 451..452 "b" +| | Semicolon 452..453 +| | | Semicolon 452..453 ";" +| | EndLine 453..455 +| | | EndLine 453..455 "\r\n" +| RCurly 455..456 +| | RCurly 455..456 "}" From 379c303ea77aac2806e58a87ac0b1e51577f0dbf Mon Sep 17 00:00:00 2001 From: Truc Vy <92658621+NTTVy03@users.noreply.github.com> Date: Thu, 15 May 2025 23:06:02 +0700 Subject: [PATCH 59/59] docs: remove unused+ update README (#71) * chore: remove all unused files from the project * chore: refactor Cargo.toml files to use workspace.dependencies * refactor: extract syntax test utils into a separate test module * docs: update README with installation, build, and debug instructions * docs: remove unused note for snapshot * docs: remove circom installation --- Cargo.toml | 34 +++++++-- README.md | 74 ++++++++++++++++--- SNAPSHOT_TEST.md | 11 --- crates/common/Cargo.toml | 9 --- crates/common/src/lib.rs | 1 - crates/database/Cargo.toml | 10 --- crates/database/src/lib.rs | 1 - crates/database/src/main.rs | 3 - crates/lsp/Cargo.toml | 37 +++------- crates/parser/Cargo.toml | 21 ++---- crates/parser/src/grammar/statement.rs | 2 - crates/syntax/Cargo.toml | 15 ++-- crates/syntax/src/lib.rs | 2 - crates/syntax/src/syntax.rs | 7 +- .../{view_syntax.rs => syntax/test_utils.rs} | 30 +++++--- crates/syntax/src/utils.rs | 10 --- xtask/Cargo.toml | 8 +- 17 files changed, 144 insertions(+), 131 deletions(-) delete mode 100644 SNAPSHOT_TEST.md delete mode 100644 crates/common/Cargo.toml delete mode 100644 crates/common/src/lib.rs delete mode 100644 crates/database/Cargo.toml delete mode 100644 crates/database/src/lib.rs delete mode 100644 crates/database/src/main.rs rename crates/syntax/src/{view_syntax.rs => syntax/test_utils.rs} (70%) delete mode 100644 crates/syntax/src/utils.rs diff --git a/Cargo.toml b/Cargo.toml index bfbc8e4..45e1d9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,14 +2,36 @@ [workspace] members = ["crates/*", "xtask/"] +resolver = "2" [workspace.dependencies] -parser = {path = "./crates/parser", version = "0.1.0"} -vfs = {path = "./crates/vfs", version = "0.1.0"} -syntax = {path = './crates/syntax', version = "0.1.0"} -circom-lsp = {path = './crates/lsp', version = "*"} -common = { path = './crates/common', version = "*"} -database = {path = "./crates/database", version = "*"} +# Internal crates +parser = { path = "./crates/parser" } +vfs = { path = "./crates/vfs" } +syntax = { path = "./crates/syntax" } +circom-lsp = { path = "./crates/lsp" } + +# External crates +logos = "0.12.0" +rowan = "0.15.13" +lsp-types = "0.94.1" +lsp-server = "0.7.6" + +serde = "1.0.216" +serde_json = "1.0.78" + +anyhow = "1.0.79" +dashmap = "5.5.3" +path-absolutize = "3.1.1" + +# For testing +insta = { version = "1.41.1" } + +[profile.dev.package.insta] +opt-level = 3 + +[profile.dev.package.similar] +opt-level = 3 [workspace.package] rust-version = "1.71" diff --git a/README.md b/README.md index fbfbf04..70fe09c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,65 @@ -# Install -Install follow those commands: - -```bash -git clone https://github.com/vuvoth/ccls -cd ccls -cargo xtask install --server -cargo xtask install --client -``` +# CCLS + +A language server for [Circom](https://docs.circom.io/), built with Rust and TypeScript. + +## ๐Ÿš€ Installation + +1. **Clone the repository:** + ```bash + git clone https://github.com/vuvoth/ccls.git + cd ccls + ``` + +2. **Install Rust** (if not already installed): + ๐Ÿ‘‰ https://www.rust-lang.org/tools/install + +3. **Build or test the project:** + ```bash + cargo test # Run tests + cargo build # Build the project + ``` + +--- + +## ๐Ÿงช Running Tests (with `insta` snapshots) + +Optional, but recommended for snapshot testing. + +1. **Install `cargo-insta`:** + ```bash + curl -LsSf https://insta.rs/install.sh | sh + ``` + +2. **Run the tests:** + ```bash + cargo test + ``` + +3. **Review snapshot changes:** + ```bash + cargo insta review + ``` + +๐Ÿ“˜ More info: [Insta Quickstart](https://insta.rs/docs/quickstart/) + +--- + +## ๐Ÿž Debugging the Extension + +1. **Install CCLS server and client:** + ```bash + cargo xtask install --server + cargo xtask install --client + npm audit fix --force # optional + ``` + +2. **Run the extension in VSCode:** + - Open the `ccls` project in VSCode. + - Open the *Run and Debug* panel. + - Select `Run Extension (Debug Build)` and start debugging. + +3. A new VSCode window will open. + Open a Circom file and try features like **Go to Definition**. + +--- + diff --git a/SNAPSHOT_TEST.md b/SNAPSHOT_TEST.md deleted file mode 100644 index 304166f..0000000 --- a/SNAPSHOT_TEST.md +++ /dev/null @@ -1,11 +0,0 @@ -# Snapshot Test - -* Run all tests: - ``` - cargo test - ``` - -* Review snapshot changes - ``` - cargo insta review - ``` \ No newline at end of file diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml deleted file mode 100644 index b7ee3f6..0000000 --- a/crates/common/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "common" -version = "0.1.0" -edition = "2021" -rust-version.workspace = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/common/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/database/Cargo.toml b/crates/database/Cargo.toml deleted file mode 100644 index 58ea405..0000000 --- a/crates/database/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "database" -version = "0.1.0" -edition = "2021" -rust-version.workspace = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -rowan = "0.15.13" diff --git a/crates/database/src/lib.rs b/crates/database/src/lib.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/database/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/database/src/main.rs b/crates/database/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/crates/database/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/crates/lsp/Cargo.toml b/crates/lsp/Cargo.toml index 1e410f8..d0d0726 100644 --- a/crates/lsp/Cargo.toml +++ b/crates/lsp/Cargo.toml @@ -6,33 +6,20 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +parser = { workspace = true } +vfs = { workspace = true } +syntax = { workspace = true } -env_logger = "0.9.0" -serde_json = "1.0.78" -serde = { version = "1.0", features = ["derive"] } -log = "0.4.18" +rowan = { workspace = true } +lsp-server = { workspace = true } +lsp-types = { workspace = true, features = ["proposed"] } -lsp-server = "0.7.6" +serde_json = { workspace = true } +serde = { workspace = true, features = ["derive"] } -rowan = "0.15.15" - -lsp-types = {version = "0.94.1", features = ["proposed"]} -parser.workspace = true -vfs.workspace = true -syntax.workspace = true - -anyhow = "1.0.79" -dashmap = "5.5.3" -path-absolutize = "3.1.1" - -[profile] -dev.debug = 2 +anyhow = { workspace = true } +dashmap = { workspace = true } +path-absolutize = { workspace = true } [dev-dependencies] -# for snapshot testing, yaml format -insta = { version = "1.41.1", features = ["yaml"] } - -[profile.dev.package] -# compile slightly slower once, but use less memory, have faster diffs -insta.opt-level = 3 -similar.opt-level = 3 +insta = { workspace = true, features = ["yaml"] } diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 0173d54..6eb11c7 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -6,21 +6,10 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -logos = "0.12.0" -lsp-types = {version = "0.94.1", features = ["proposed"]} -rowan = "0.15.15" -num-traits = "0.2" -num-derive = "0.2" -serde = "1.0.216" - -[profile.dev] -debug = 2 +logos = { workspace = true } +lsp-types = { workspace = true, features = ["proposed"] } +rowan = { workspace = true } +serde = { workspace = true } [dev-dependencies] -# for snapshot testing, yaml format -insta = { version = "1.41.1", features = ["yaml"] } - -[profile.dev.package] -# compile slightly slower once, but use less memory, have faster diffs -insta.opt-level = 3 -similar.opt-level = 3 \ No newline at end of file +insta = { workspace = true, features = ["yaml"] } diff --git a/crates/parser/src/grammar/statement.rs b/crates/parser/src/grammar/statement.rs index d2d585f..93976d9 100644 --- a/crates/parser/src/grammar/statement.rs +++ b/crates/parser/src/grammar/statement.rs @@ -1,5 +1,3 @@ -use crate::token_kind::TokenKind; - use super::{block::block, expression::expression, *}; pub(super) fn statement(p: &mut Parser) { diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 795f0b1..2ea37aa 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -7,15 +7,10 @@ rust-version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rowan = "0.15.13" -parser.workspace = true -lsp-types = {version = "0.94.1", features = ["proposed"]} +parser = { workspace = true } -[dev-dependencies] -# for snapshot testing, yaml format -insta = { version = "1.41.1", features = ["yaml"] } +rowan = { workspace = true } +lsp-types = { workspace = true, features = ["proposed"] } -[profile.dev.package] -# compile slightly slower once, but use less memory, have faster diffs -insta.opt-level = 3 -similar.opt-level = 3 \ No newline at end of file +[dev-dependencies] +insta = { workspace = true, features = ["yaml"] } diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 81704de..622b4ac 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -1,5 +1,3 @@ pub mod abstract_syntax_tree; pub mod syntax; pub mod syntax_node; -mod utils; -mod view_syntax; diff --git a/crates/syntax/src/syntax.rs b/crates/syntax/src/syntax.rs index bc07f3b..f7a87ca 100644 --- a/crates/syntax/src/syntax.rs +++ b/crates/syntax/src/syntax.rs @@ -87,11 +87,16 @@ pub fn syntax_node_from_source(source: &str, scope: Scope) -> SyntaxNode { syntax } +#[cfg(test)] +mod test_utils; + #[cfg(test)] mod tests { - use crate::test_syntax; use parser::grammar::entry::Scope; + use crate::syntax::test_utils::view_ast; + use crate::test_syntax; + #[test] fn pragma_happy_test() { test_syntax!("/src/test_files/happy/pragma.circom", Scope::Pragma); diff --git a/crates/syntax/src/view_syntax.rs b/crates/syntax/src/syntax/test_utils.rs similarity index 70% rename from crates/syntax/src/view_syntax.rs rename to crates/syntax/src/syntax/test_utils.rs index 270c710..6a876ef 100644 --- a/crates/syntax/src/view_syntax.rs +++ b/crates/syntax/src/syntax/test_utils.rs @@ -1,17 +1,20 @@ -use crate::syntax_node::SyntaxNode; - pub use rowan::{NodeOrToken, WalkEvent}; -fn level_str(level: u32) -> String { - let mut ans = String::from(""); +use crate::syntax_node::SyntaxNode; - for _i in 0..level { - ans.push_str("| "); - } - ans +#[macro_export] +macro_rules! test_syntax { + ($file_path:expr, $scope: expr) => { + let crate_path = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + + let full_path = format!("{}{}", crate_path, $file_path); + let source = std::fs::read_to_string(full_path).expect("Should not failed"); + let syntax = crate::syntax::syntax_node_from_source(&source, $scope); + insta::assert_snapshot!($file_path, view_ast(&syntax)); + }; } -pub(crate) fn view_ast(node: &SyntaxNode) -> String { +pub fn view_ast(node: &SyntaxNode) -> String { let mut level = 0; let mut result = String::new(); for event in node.preorder_with_tokens() { @@ -47,3 +50,12 @@ pub(crate) fn view_ast(node: &SyntaxNode) -> String { } return result; } + +fn level_str(level: u32) -> String { + let mut ans = String::from(""); + + for _i in 0..level { + ans.push_str("| "); + } + ans +} diff --git a/crates/syntax/src/utils.rs b/crates/syntax/src/utils.rs deleted file mode 100644 index f173682..0000000 --- a/crates/syntax/src/utils.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[macro_export] -macro_rules! test_syntax { - ($file_path:expr, $scope: expr) => { - let crate_path = std::env::var("CARGO_MANIFEST_DIR").unwrap(); - let full_path = format!("{}{}", crate_path, $file_path); - let source = std::fs::read_to_string(full_path).expect("Should not failed"); - let syntax = crate::syntax::syntax_node_from_source(&source, $scope); - insta::assert_snapshot!($file_path, crate::view_syntax::view_ast(&syntax)); - }; -} diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 5fe9391..7b711b3 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -7,11 +7,7 @@ edition = "2021" rust-version.workspace = true [dependencies] -anyhow = "1.0.62" -flate2 = "1.0.24" -write-json = "0.1.2" +anyhow = { workspace = true } xshell = "0.2.2" xflags = "0.3.0" -time = { version = "0.3", default-features = false } -zip = { version = "0.6", default-features = false, features = ["deflate", "time"] } -# Avoid adding more dependencies to this crate \ No newline at end of file +# Avoid adding more dependencies to this crate