diff --git a/src/ir/ast.rs b/src/ir/ast.rs index 79e487d..fd48e00 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -130,6 +130,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 d4f02dd..d7be3f6 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_common.rs b/src/parser/parser_common.rs index bb739d3..6a7121a 100644 --- a/src/parser/parser_common.rs +++ b/src/parser/parser_common.rs @@ -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"; @@ -72,11 +73,16 @@ 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), + // Ensure the keyword is not followed by an identifier character (letter, digit, or underscore) + peek(not(identifier_start_or_continue)), + ), + multispace0, ) } diff --git a/src/parser/parser_stmt.rs b/src/parser/parser_stmt.rs index 264412a..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, + 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; @@ -25,6 +25,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, @@ -106,6 +107,34 @@ fn parse_if_else_statement(input: &str) -> IResult<&str, Statement> { )(input) } +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; + + loop { + let result = tuple((keyword(ELIF_KEYWORD), 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(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(( @@ -275,6 +304,7 @@ fn parse_function_definition_statement(input: &str) -> IResult<&str, Statement> keyword(DEF_KEYWORD), preceded(multispace1, identifier), delimited( + // Corrigido: Removido o comentário que quebrava a sintaxe char::<&str, Error<&str>>(LEFT_PAREN), separated_list0( tuple(( @@ -290,6 +320,7 @@ fn parse_function_definition_statement(input: &str) -> IResult<&str, Statement> preceded(multispace0, parse_type), parse_block, )), + // Corrigido: O nome da variável 'args' agora está correto |(_, name, args, _, t, block)| { Statement::FuncDef(Function { name: name.to_string(), @@ -475,6 +506,99 @@ mod tests { 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); + } //TODO: Apresentar Parser de TestDef (Testes) mod testdef_tests { use super::*;