diff --git a/src/interpreter/statement_execute.rs b/src/interpreter/statement_execute.rs index 2c9e44f..71fd1c0 100644 --- a/src/interpreter/statement_execute.rs +++ b/src/interpreter/statement_execute.rs @@ -75,6 +75,60 @@ pub fn execute( } } + Statement::For(var, expr, stmt) => { + let coll = eval(*expr, &new_env)?; + + match coll { + // Lista de valores + Expression::ListValue(items) => { + new_env.push(); + for item in items { + new_env.map_variable(var.clone(), true, item); + new_env = execute(*stmt.clone(), &new_env)?; + } + new_env.pop(); + Ok(new_env) + } + + // String - itera sobre caracteres + Expression::CString(s) => { + new_env.push(); + for ch in s.chars() { + let char_value = Expression::CString(ch.to_string()); + new_env.map_variable(var.clone(), true, char_value); + new_env = execute(*stmt.clone(), &new_env)?; + } + new_env.pop(); + Ok(new_env) + } + + // Tupla (assumindo que você tem Expression::Tuple) + Expression::Tuple(items) => { + new_env.push(); + for item in items { + new_env.map_variable(var.clone(), true, item); + new_env = execute(*stmt.clone(), &new_env)?; + } + new_env.pop(); + Ok(new_env) + } + + // Constructor (já existia) + Expression::Constructor(_, items) => { + new_env.push(); + for item_expr in items { + let item_value = *item_expr.clone(); + new_env.map_variable(var.clone(), true, item_value); + new_env = execute(*stmt.clone(), &new_env)?; + } + new_env.pop(); + Ok(new_env) + } + + _ => Err((format!("Cannot iterate over {:?}", coll), None)), + } + } + Statement::Sequence(s1, s2) => { new_env = execute(*s1, &new_env)?; execute(*s2, &new_env) diff --git a/src/ir/ast.rs b/src/ir/ast.rs index ba580a1..cba61f0 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -134,4 +134,5 @@ pub enum Statement { FuncDef(Function), Return(Box), TypeDeclaration(Name, Vec), + Tuple(Vec) } \ No newline at end of file diff --git a/src/type_checker/statement_type_checker.rs b/src/type_checker/statement_type_checker.rs index 5c6835e..40546e4 100644 --- a/src/type_checker/statement_type_checker.rs +++ b/src/type_checker/statement_type_checker.rs @@ -141,6 +141,28 @@ fn check_while_stmt( Ok(new_env) } +// Função auxiliar para determinar o tipo do elemento iterável +fn get_iterable_element_type(expr_type: &Type) -> Result { + match expr_type { + Type::TList(base_type) => Ok((**base_type).clone()), + Type::TString => Ok(Type::TString), // Caracteres como strings + Type::TTuple(types) => { + if types.is_empty() { + return Err("[Type Error] Cannot iterate over empty tuple type".to_string()); + } + + // Verificar se todos os tipos são iguais (tupla homogênea) + let first_type = &types[0]; + if types.iter().all(|t| t == first_type) { + Ok(first_type.clone()) + } else { + Err("[Type Error] Can only iterate over homogeneous tuples (all elements same type)".to_string()) + } + } + _ => Err(format!("[Type Error] Type {:?} is not iterable", expr_type)) + } +} + fn check_for_stmt( var: Name, expr: Box, @@ -148,33 +170,26 @@ fn check_for_stmt( env: &Environment, ) -> Result, ErrorMessage> { let mut new_env = env.clone(); - let _var_type = env.lookup(&var); + + // Avaliar o tipo da expressão iterável let expr_type = check_expr(*expr, &new_env)?; - match expr_type { - Type::TList(base_type) => { - if let Some((_, t)) = env.lookup(&var) { - if t == *base_type || *base_type == Type::TAny { - new_env = check_stmt(*stmt, &new_env)?; - return Ok(new_env); - } else { - return Err(format!( - "[TypeError] Type mismatch between {:?} and {:?}", - t, base_type - )); - } - } else { - new_env.map_variable(var.clone(), false, *base_type); - new_env = check_stmt(*stmt, &new_env)?; - return Ok(new_env); - } - } - _ => { - return Err(format!( - "[TypeError] Expecting a List type, but found a {:?}", - expr_type - )) - } - } + + // Determinar o tipo do elemento + let element_type = get_iterable_element_type(&expr_type)?; + + // Criar novo escopo para o loop + new_env.push(); + + // Mapear a variável iteradora no novo escopo + new_env.map_variable(var.clone(), false, element_type); + + // Verificar o corpo do loop no novo escopo + new_env = check_stmt(*stmt, &new_env)?; + + // Remover o escopo do loop + new_env.pop(); + + Ok(new_env) } fn check_func_def_stmt( diff --git a/tests/parser_tests.rs b/tests/parser_tests.rs index 937e3c2..e634540 100644 --- a/tests/parser_tests.rs +++ b/tests/parser_tests.rs @@ -109,6 +109,45 @@ mod expression_tests { assert_eq!(rest, ""); assert_eq!(result, expected); } + + #[test] + fn test_tuple_literals() { + let cases = vec![ + ( + "(1, 2, 3)", + Expression::Tuple(vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(3), + ]), + ), + ( + "(\"hello\", True)", + Expression::Tuple(vec![ + Expression::CString("hello".to_string()), + Expression::CTrue, + ]), + ), + ("()", Expression::Tuple(vec![])), + ( + "(42,)", + Expression::Tuple(vec![Expression::CInt(42)]), + ), + ( + "((1, 2), (3, 4))", + Expression::Tuple(vec![ + Expression::Tuple(vec![Expression::CInt(1), Expression::CInt(2)]), + Expression::Tuple(vec![Expression::CInt(3), Expression::CInt(4)]), + ]), + ), + ]; + + for (input, expected) in cases { + let (rest, result) = parse_expression(input).unwrap(); + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + } } // Statement Tests @@ -204,6 +243,75 @@ mod statement_tests { assert_eq!(result, expected); } + #[test] + fn test_for_over_tuple() { + let cases = vec![ + ( + "for x in (1, 2, 3): x = x + 1; end", + Statement::For( + "x".to_string(), + Box::new(Expression::Tuple(vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(3), + ])), + Box::new(Statement::Block(vec![Statement::Assignment( + "x".to_string(), + Box::new(Expression::Add( + Box::new(Expression::Var("x".to_string())), + Box::new(Expression::CInt(1)), + )), + )])), + ), + ), + ( + "for item in (\"a\", \"b\"): val x = item; end", + Statement::For( + "item".to_string(), + Box::new(Expression::Tuple(vec![ + Expression::CString("a".to_string()), + Expression::CString("b".to_string()), + ])), + Box::new(Statement::Block(vec![Statement::ValDeclaration( + "x".to_string(), + Box::new(Expression::Var("item".to_string())), + )])), + ), + ), + ( + "for x in (): val y = 1; end", + Statement::For( + "x".to_string(), + Box::new(Expression::Tuple(vec![])), + Box::new(Statement::Block(vec![Statement::ValDeclaration( + "y".to_string(), + Box::new(Expression::CInt(1)), + )])), + ), + ), + ( + "for t in ((1,2), (3,4)): val x = t; end", + Statement::For( + "t".to_string(), + Box::new(Expression::Tuple(vec![ + Expression::Tuple(vec![Expression::CInt(1), Expression::CInt(2)]), + Expression::Tuple(vec![Expression::CInt(3), Expression::CInt(4)]), + ])), + Box::new(Statement::Block(vec![Statement::ValDeclaration( + "x".to_string(), + Box::new(Expression::Var("t".to_string())), + )])), + ), + ), + ]; + + for (input, expected) in cases { + let (rest, result) = parse_statement(input).unwrap(); + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + } + #[test] #[ignore] fn test_function_definitions() {