From a125ed9aee5b2c810674d44da766f8282edb19f6 Mon Sep 17 00:00:00 2001 From: ptrcnull Date: Fri, 9 May 2025 16:56:27 +0200 Subject: [PATCH 1/2] add parsing functions --- src/formatter.rs | 20 ++++++++++++++++++++ src/interpreter.rs | 2 +- src/parser.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/formatter.rs b/src/formatter.rs index 9c740b7..524e924 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -628,6 +628,26 @@ impl Formatter { result.push_str("fi"); + result + } + Node::Function { name, list, has_keyword } => { + let mut result = self.indent(); + if *has_keyword { + result.push_str("function "); + } + result.push_str(name); + result.push_str("() {"); + result.push('\n'); + + self.indent_level += 1; + result.push_str(&self.format(list)); + self.indent_level -= 1; + + result.push('\n'); + result.push_str(&self.indent()); + + result.push('}'); + result } } diff --git a/src/interpreter.rs b/src/interpreter.rs index 9e511dd..60632a5 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1306,7 +1306,7 @@ impl Interpreter { Ok(0) } - &Node::IfStatement { .. } | &Node::ElifBranch { .. } | &Node::ElseBranch { .. } => { + &Node::IfStatement { .. } | &Node::ElifBranch { .. } | &Node::ElseBranch { .. } | &Node::Function { .. } => { todo!() } } diff --git a/src/parser.rs b/src/parser.rs index ac6a4c0..2c9e031 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -51,6 +51,11 @@ pub enum Node { ElseBranch { consequence: Box, }, + Function { + name: String, + list: Box, + has_keyword: bool, + }, } /// Redirection types @@ -107,6 +112,10 @@ impl Parser { if self.peek_token.kind == TokenKind::Assignment { return Some(self.parse_assignment()); } + // Check for LParen (function without keyword) + if self.peek_token.kind == TokenKind::LParen { + return Some(self.parse_function(false)); + } // Regular command Some(self.parse_command()) @@ -121,6 +130,10 @@ impl Parser { Some(Node::Comment(comment)) } TokenKind::ExtGlob(_) => Some(self.parse_extglob()), + TokenKind::Function => { + self.next_token(); + Some(self.parse_function(true)) + } _ => None, } } @@ -221,6 +234,27 @@ impl Parser { } } + fn parse_function(&mut self, has_keyword: bool) -> Node { + let name = self.current_token.value.clone(); + + if self.peek_token.kind == TokenKind::LParen { + self.next_token(); // Skip LParen + self.next_token(); // Skip RParen + } + + self.next_token(); // Skip LBrace + + let list = self.parse_until_token_kind(TokenKind::RBrace); + + self.next_token(); // Skip RBrace + + Node::Function { + name, + list: Box::new(list), + has_keyword, + } + } + // method to parse statements until a specific token kind is encountered fn parse_until_token_kind(&mut self, stop_at: TokenKind) -> Node { let mut statements = Vec::new(); From 0eb0f1b63fa09f40f71b621b6e17d6ef549dae35 Mon Sep 17 00:00:00 2001 From: ptrcnull Date: Fri, 9 May 2025 17:06:44 +0200 Subject: [PATCH 2/2] add tests for parsing functions --- src/parser.rs | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 2c9e031..9e6d604 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1423,9 +1423,40 @@ function hello() { hello World "#; - // This would require additional parsing logic not present in the current code - // Just verify it doesn't panic - let _result = parse_test(input); + let result = parse_test(input); + match result { + Node::List { + statements, + operators, + } => { + assert_eq!(statements.len(), 2); + assert_eq!(operators.len(), 2); + + match &statements[0] { + Node::Function { + name, + list, + has_keyword, + } => { + assert_eq!(name, "hello"); + assert_eq!(*has_keyword, true); + + match &**list { + Node::List { + statements, + operators, + } => { + assert_eq!(statements.len(), 1); + assert_eq!(operators.len(), 0); + } + _ => panic!("Expected List node inside function"), + } + } + _ => panic!("Expected Function node"), + } + } + _ => panic!("Expected List node"), + } } #[test]