From b4629af6b8c6c1b108612836616d70ad9aa89dbe Mon Sep 17 00:00:00 2001 From: GUstavo Date: Wed, 2 Jul 2025 12:00:39 -0300 Subject: [PATCH 1/4] =?UTF-8?q?adi=C3=A7=C3=A3o=20do=20parser,=20adi=C3=A7?= =?UTF-8?q?=C3=A3o=20na=20ast=20e=20keywords?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ir/ast.rs | 4 ++++ src/parser/keywords.rs | 1 + src/parser/parser_stmt.rs | 42 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/ir/ast.rs b/src/ir/ast.rs index ba580a1..9e83fe8 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -119,6 +119,10 @@ pub enum Statement { ValDeclaration(Name, Box), Assignment(Name, Box), IfThenElse(Box, Box, Option>), + IfChain { + branches: Vec<(Box, Box)>, + else_branch: Option>, + }, While(Box, Box), For(Name, Box, Box), Block(Vec), diff --git a/src/parser/keywords.rs b/src/parser/keywords.rs index 5d528d8..1d9d878 100644 --- a/src/parser/keywords.rs +++ b/src/parser/keywords.rs @@ -2,6 +2,7 @@ pub const KEYWORDS: &[&str] = &[ "if", "in", "else", + "elif", "def", "while", "for", diff --git a/src/parser/parser_stmt.rs b/src/parser/parser_stmt.rs index bdcebdb..b262fcb 100644 --- a/src/parser/parser_stmt.rs +++ b/src/parser/parser_stmt.rs @@ -99,6 +99,44 @@ fn parse_if_else_statement(input: &str) -> IResult<&str, Statement> { )(input) } +pub fn parse_if_chain_statement(input: &str) -> IResult<&str, Statement> { + let (input, _) = keyword(IF_KEYWORD)(input)?; + let (input, cond_if) = preceded(multispace1, parse_expression)(input)?; + let (input, block_if) = parse_block(input)?; + + let mut branches = vec![(Box::new(cond_if), Box::new(block_if))]; + let mut current_input = input; + + loop { + let result = tuple(( + multispace0, + keyword(ELIF_KEYWORD), + preceded(multispace1, parse_expression), + parse_block, + ))(current_input); + + match result { + Ok((next_input, (_, _, cond_elif, block_elif))) => { + branches.push((Box::new(cond_elif), Box::new(block_elif))); + current_input = next_input; + } + Err(_) => break, + } + } + let (input, else_branch) = opt(preceded( + tuple((multispace0, keyword(ELSE_KEYWORD))), + parse_block, + ))(current_input)?; + + Ok(( + input, + Statement::IfChain { + branches, + else_branch: else_branch.map(Box::new), + }, + )) +} + fn parse_while_statement(input: &str) -> IResult<&str, Statement> { map( tuple(( @@ -155,7 +193,7 @@ fn parse_function_definition_statement(input: &str) -> IResult<&str, Statement> keyword(DEF_KEYWORD), preceded(multispace1, identifier), delimited( - char::<&str, Error<&str>>(LEFT_PAREN), + char:// Tenta parsear um else opcional:<&str, Error<&str>>(LEFT_PAREN), separated_list0( tuple(( multispace0, @@ -170,7 +208,7 @@ fn parse_function_definition_statement(input: &str) -> IResult<&str, Statement> preceded(multispace0, parse_type), parse_block, )), - |(_, name, args, _, t, block)| { + |(_, name, ar// Tenta parsear um else opcionalgs, _, t, block)| { Statement::FuncDef(Function { name: name.to_string(), kind: t, From 4f179e0178d414048f6108e8099c0a55524b571d Mon Sep 17 00:00:00 2001 From: jm-236 Date: Wed, 2 Jul 2025 15:36:12 -0300 Subject: [PATCH 2/4] =?UTF-8?q?test:=20implementa=C3=A7=C3=A3o=20dos=20tes?= =?UTF-8?q?tes=20da=20fun=C3=A7=C3=A3o=20parse=5Fif=5Fchain=20e=20corre?= =?UTF-8?q?=C3=A7=C3=A3o=20de=20erros.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ir/ast.rs | 4 +- src/parser/parser_common.rs | 15 +++-- src/parser/parser_stmt.rs | 123 ++++++++++++++++++++++++++++++------ 3 files changed, 114 insertions(+), 28 deletions(-) diff --git a/src/ir/ast.rs b/src/ir/ast.rs index 9e83fe8..fc67aab 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -120,8 +120,8 @@ pub enum Statement { Assignment(Name, Box), IfThenElse(Box, Box, Option>), IfChain { - branches: Vec<(Box, Box)>, - else_branch: Option>, + branches: Vec<(Box, Box)>, + else_branch: Option>, }, While(Box, Box), For(Name, Box, Box), diff --git a/src/parser/parser_common.rs b/src/parser/parser_common.rs index 065a742..4b4b44b 100644 --- a/src/parser/parser_common.rs +++ b/src/parser/parser_common.rs @@ -1,7 +1,7 @@ use nom::{ branch::alt, bytes::complete::tag, - character::complete::{alpha1, multispace0}, + character::complete::{alpha1, multispace0, alphanumeric1}, combinator::{not, peek, recognize}, multi::many0, sequence::{delimited, terminated}, @@ -28,6 +28,7 @@ pub const END_KEYWORD: &str = "end"; // Statement keyword constants pub const IF_KEYWORD: &str = "if"; +pub const ELIF_KEYWORD: &str = "elif"; pub const ELSE_KEYWORD: &str = "else"; pub const WHILE_KEYWORD: &str = "while"; pub const FOR_KEYWORD: &str = "for"; @@ -67,11 +68,15 @@ pub fn separator<'a>(sep: &'static str) -> impl FnMut(&'a str) -> IResult<&'a st } /// Parses a reserved keyword (e.g., "if") surrounded by optional spaces -/// Fails if followed by an identifier character +/// A implementação da função keyword foi alterada para que seja garantida que a keyword seja uma palavra completa e seja separada por um espaço pub fn keyword<'a>(kw: &'static str) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> { - terminated( - delimited(multispace0, tag(kw), multispace0), - not(peek(identifier_start_or_continue)), + delimited( + multispace0, + terminated( + tag(kw), + peek(not(alphanumeric1)), + ), + multispace0, ) } diff --git a/src/parser/parser_stmt.rs b/src/parser/parser_stmt.rs index b262fcb..ab2c57a 100644 --- a/src/parser/parser_stmt.rs +++ b/src/parser/parser_stmt.rs @@ -13,7 +13,7 @@ use crate::ir::ast::{FormalArgument, Function, Statement}; use crate::parser::parser_common::{ identifier, keyword, ASSERT_KEYWORD, COLON_CHAR, COMMA_CHAR, DEF_KEYWORD, ELSE_KEYWORD, END_KEYWORD, EQUALS_CHAR, FOR_KEYWORD, FUNCTION_ARROW, IF_KEYWORD, IN_KEYWORD, LEFT_PAREN, - RIGHT_PAREN, SEMICOLON_CHAR, VAL_KEYWORD, VAR_KEYWORD, WHILE_KEYWORD, + RIGHT_PAREN, SEMICOLON_CHAR, VAL_KEYWORD, VAR_KEYWORD, WHILE_KEYWORD, ELIF_KEYWORD }; use crate::parser::parser_expr::parse_expression; use crate::parser::parser_type::parse_type; @@ -100,34 +100,25 @@ fn parse_if_else_statement(input: &str) -> IResult<&str, Statement> { } pub fn parse_if_chain_statement(input: &str) -> IResult<&str, Statement> { - let (input, _) = keyword(IF_KEYWORD)(input)?; - let (input, cond_if) = preceded(multispace1, parse_expression)(input)?; - let (input, block_if) = parse_block(input)?; - + + let (input_after_if, _) = keyword(IF_KEYWORD)(input)?; + let (input_after_expr, cond_if) = parse_expression(input_after_if)?; + let (input_after_block, block_if) = parse_block(input_after_expr)?; + let mut branches = vec![(Box::new(cond_if), Box::new(block_if))]; - let mut current_input = input; + let mut current_input = input_after_block; loop { - let result = tuple(( - multispace0, - keyword(ELIF_KEYWORD), - preceded(multispace1, parse_expression), - parse_block, - ))(current_input); - + let result = tuple((keyword(ELIF_KEYWORD), parse_expression, parse_block))(current_input); match result { - Ok((next_input, (_, _, cond_elif, block_elif))) => { + Ok((next_input, (_, cond_elif, block_elif))) => { branches.push((Box::new(cond_elif), Box::new(block_elif))); current_input = next_input; } Err(_) => break, } } - let (input, else_branch) = opt(preceded( - tuple((multispace0, keyword(ELSE_KEYWORD))), - parse_block, - ))(current_input)?; - + let (input, else_branch) = opt(preceded(keyword(ELSE_KEYWORD), parse_block))(current_input)?; Ok(( input, Statement::IfChain { @@ -193,7 +184,8 @@ fn parse_function_definition_statement(input: &str) -> IResult<&str, Statement> keyword(DEF_KEYWORD), preceded(multispace1, identifier), delimited( - char:// Tenta parsear um else opcional:<&str, Error<&str>>(LEFT_PAREN), + // Corrigido: Removido o comentário que quebrava a sintaxe + char::<&str, Error<&str>>(LEFT_PAREN), separated_list0( tuple(( multispace0, @@ -208,7 +200,8 @@ fn parse_function_definition_statement(input: &str) -> IResult<&str, Statement> preceded(multispace0, parse_type), parse_block, )), - |(_, name, ar// Tenta parsear um else opcionalgs, _, t, block)| { + // Corrigido: O nome da variável 'args' agora está correto + |(_, name, args, _, t, block)| { Statement::FuncDef(Function { name: name.to_string(), kind: t, @@ -381,4 +374,92 @@ mod tests { let parsed = parse_formal_argument(input).unwrap().1; assert_eq!(parsed, expected); } + + #[test] + fn test_parse_if_chain_statement() { + + // Cenário 1: Apenas um "if", sem "elif" ou "else". + let input_if_only = "if True: x = 1; end"; + let expected_if_only = Statement::IfChain { + branches: vec![( + Box::new(Expression::CTrue), + Box::new(Statement::Block(vec![Statement::Assignment( + "x".to_string(), + Box::new(Expression::CInt(1)), + )])), + )], + else_branch: None, + }; + let (_, parsed_if_only) = parse_if_chain_statement(input_if_only).unwrap(); + assert_eq!(parsed_if_only, expected_if_only); + + // Cenário 2: Um "if" com "else", mas sem "elif". + let input_if_else = "if False: x = 1; end else: y = 2; end"; + let expected_if_else = Statement::IfChain { + branches: vec![( + Box::new(Expression::CFalse), + Box::new(Statement::Block(vec![Statement::Assignment( + "x".to_string(), + Box::new(Expression::CInt(1)), + )])), + )], + else_branch: Some(Box::new(Statement::Block(vec![Statement::Assignment( + "y".to_string(), + Box::new(Expression::CInt(2)), + )]))), + }; + let (_, parsed_if_else) = parse_if_chain_statement(input_if_else).unwrap(); + assert_eq!(parsed_if_else, expected_if_else); + + // Cenário 3: "if", um "elif", e um "else". + let input_if_elif_else = "if a: x = 1; end elif b: y = 2; end else: z = 3; end"; + let expected_if_elif_else = Statement::IfChain { + branches: vec![ + ( + Box::new(Expression::Var("a".to_string())), + Box::new(Statement::Block(vec![Statement::Assignment( + "x".to_string(), + Box::new(Expression::CInt(1)), + )])), + ), + ( + Box::new(Expression::Var("b".to_string())), + Box::new(Statement::Block(vec![Statement::Assignment( + "y".to_string(), + Box::new(Expression::CInt(2)), + )])), + ), + ], + else_branch: Some(Box::new(Statement::Block(vec![Statement::Assignment( + "z".to_string(), + Box::new(Expression::CInt(3)), + )]))), + }; + let (_, parsed_if_elif_else) = parse_if_chain_statement(input_if_elif_else).unwrap(); + assert_eq!(parsed_if_elif_else, expected_if_elif_else); + + // Cenário 4: "if" com múltiplos "elif" e sem "else". + let input_multi_elif = "if a: x=1; end elif b: y=2; end elif c: z=3; end"; + let expected_multi_elif = Statement::IfChain { + branches: vec![ + ( + Box::new(Expression::Var("a".to_string())), + Box::new(Statement::Block(vec![Statement::Assignment("x".to_string(), Box::new(Expression::CInt(1)))])), + ), + ( + Box::new(Expression::Var("b".to_string())), + Box::new(Statement::Block(vec![Statement::Assignment("y".to_string(), Box::new(Expression::CInt(2)))])), + ), + ( + Box::new(Expression::Var("c".to_string())), + Box::new(Statement::Block(vec![Statement::Assignment("z".to_string(), Box::new(Expression::CInt(3)))])), + ), + ], + else_branch: None, + }; + let (_, parsed_multi_elif) = parse_if_chain_statement(input_multi_elif).unwrap(); + assert_eq!(parsed_multi_elif, expected_multi_elif); + } } + + From 9f6c30f71671a7102b87c7b5670c86b7e96f7897 Mon Sep 17 00:00:00 2001 From: jm-236 Date: Thu, 10 Jul 2025 12:35:37 -0300 Subject: [PATCH 3/4] feat: Adiciona parser if_chain ao parser_stmt --- src/parser/parser_stmt.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/parser/parser_stmt.rs b/src/parser/parser_stmt.rs index ab2c57a..5870d7f 100644 --- a/src/parser/parser_stmt.rs +++ b/src/parser/parser_stmt.rs @@ -23,6 +23,7 @@ pub fn parse_statement(input: &str) -> IResult<&str, Statement> { parse_var_declaration_statement, parse_val_declaration_statement, parse_assignment_statement, + parse_if_chain_statement, parse_if_else_statement, parse_while_statement, parse_for_statement, From 1dff39f2afc7bf14c1bb086891ad977c7c18042a Mon Sep 17 00:00:00 2001 From: RafaelLopes23 Date: Wed, 27 Aug 2025 16:34:13 -0300 Subject: [PATCH 4/4] chore(fmt): apply rustfmt after merging PR #52 --- src/parser/parser_stmt.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/parser/parser_stmt.rs b/src/parser/parser_stmt.rs index 43c90da..7723beb 100644 --- a/src/parser/parser_stmt.rs +++ b/src/parser/parser_stmt.rs @@ -13,9 +13,9 @@ use crate::ir::ast::Type; use crate::ir::ast::{FormalArgument, Function, Statement}; use crate::parser::parser_common::{ identifier, keyword, ASSERTEQ_KEYWORD, ASSERTFALSE_KEYWORD, ASSERTNEQ_KEYWORD, - ASSERTTRUE_KEYWORD, ASSERT_KEYWORD, COLON_CHAR, COMMA_CHAR, DEF_KEYWORD, ELSE_KEYWORD, - END_KEYWORD, EQUALS_CHAR, FOR_KEYWORD, FUNCTION_ARROW, IF_KEYWORD, IN_KEYWORD, LEFT_PAREN, - RIGHT_PAREN, SEMICOLON_CHAR, VAL_KEYWORD, VAR_KEYWORD, WHILE_KEYWORD, ELIF_KEYWORD + ASSERTTRUE_KEYWORD, ASSERT_KEYWORD, COLON_CHAR, COMMA_CHAR, DEF_KEYWORD, ELIF_KEYWORD, + ELSE_KEYWORD, END_KEYWORD, EQUALS_CHAR, FOR_KEYWORD, FUNCTION_ARROW, IF_KEYWORD, IN_KEYWORD, + LEFT_PAREN, RIGHT_PAREN, SEMICOLON_CHAR, VAL_KEYWORD, VAR_KEYWORD, WHILE_KEYWORD, }; use crate::parser::parser_expr::parse_expression; use crate::parser::parser_type::parse_type; @@ -108,11 +108,10 @@ fn parse_if_else_statement(input: &str) -> IResult<&str, Statement> { } pub fn parse_if_chain_statement(input: &str) -> IResult<&str, Statement> { - let (input_after_if, _) = keyword(IF_KEYWORD)(input)?; let (input_after_expr, cond_if) = parse_expression(input_after_if)?; let (input_after_block, block_if) = parse_block(input_after_expr)?; - + let mut branches = vec![(Box::new(cond_if), Box::new(block_if))]; let mut current_input = input_after_block; @@ -509,7 +508,6 @@ mod tests { #[test] fn test_parse_if_chain_statement() { - // Cenário 1: Apenas um "if", sem "elif" ou "else". let input_if_only = "if True: x = 1; end"; let expected_if_only = Statement::IfChain { @@ -569,22 +567,31 @@ mod tests { }; let (_, parsed_if_elif_else) = parse_if_chain_statement(input_if_elif_else).unwrap(); assert_eq!(parsed_if_elif_else, expected_if_elif_else); - + // Cenário 4: "if" com múltiplos "elif" e sem "else". let input_multi_elif = "if a: x=1; end elif b: y=2; end elif c: z=3; end"; let expected_multi_elif = Statement::IfChain { branches: vec![ ( Box::new(Expression::Var("a".to_string())), - Box::new(Statement::Block(vec![Statement::Assignment("x".to_string(), Box::new(Expression::CInt(1)))])), + Box::new(Statement::Block(vec![Statement::Assignment( + "x".to_string(), + Box::new(Expression::CInt(1)), + )])), ), ( Box::new(Expression::Var("b".to_string())), - Box::new(Statement::Block(vec![Statement::Assignment("y".to_string(), Box::new(Expression::CInt(2)))])), + Box::new(Statement::Block(vec![Statement::Assignment( + "y".to_string(), + Box::new(Expression::CInt(2)), + )])), ), ( Box::new(Expression::Var("c".to_string())), - Box::new(Statement::Block(vec![Statement::Assignment("z".to_string(), Box::new(Expression::CInt(3)))])), + Box::new(Statement::Block(vec![Statement::Assignment( + "z".to_string(), + Box::new(Expression::CInt(3)), + )])), ), ], else_branch: None, @@ -867,5 +874,3 @@ mod tests { } } } - -