Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/ir/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ pub enum Statement {
ValDeclaration(Name, Box<Expression>),
Assignment(Name, Box<Expression>),
IfThenElse(Box<Expression>, Box<Statement>, Option<Box<Statement>>),
IfChain {
branches: Vec<(Box<Expression>, Box<Statement>)>,
else_branch: Option<Box<Statement>>,
},
While(Box<Expression>, Box<Statement>),
For(Name, Box<Expression>, Box<Statement>),
Block(Vec<Statement>),
Expand Down
1 change: 1 addition & 0 deletions src/parser/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub const KEYWORDS: &[&str] = &[
"if",
"in",
"else",
"elif",
"def",
"while",
"for",
Expand Down
14 changes: 10 additions & 4 deletions src/parser/parser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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,
)
}

Expand Down
130 changes: 127 additions & 3 deletions src/parser/parser_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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((
Expand Down Expand Up @@ -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((
Expand All @@ -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(),
Expand Down Expand Up @@ -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::*;
Expand Down
Loading