From 7664192bc8f9815a775b0291074f064cfe867ca0 Mon Sep 17 00:00:00 2001 From: Layr Date: Fri, 14 Feb 2025 12:04:55 -0300 Subject: [PATCH 01/15] math inicial --- src/main.rs | 1 + src/stdlib.rs | 1 + src/stdlib/math.rs | 230 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+) create mode 100644 src/stdlib.rs create mode 100644 src/stdlib/math.rs diff --git a/src/main.rs b/src/main.rs index a2fb883..fe37829 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ pub mod interpreter; pub mod ir; pub mod parser; pub mod tc; +pub mod stdlib; fn run_test(name: &str, program: &str) -> String { let mut output = String::new(); diff --git a/src/stdlib.rs b/src/stdlib.rs new file mode 100644 index 0000000..354c7c9 --- /dev/null +++ b/src/stdlib.rs @@ -0,0 +1 @@ +pub mod math; \ No newline at end of file diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs new file mode 100644 index 0000000..b4c89ff --- /dev/null +++ b/src/stdlib/math.rs @@ -0,0 +1,230 @@ +pub fn sqrt(x: &f64) -> f64 { + x.sqrt() +} + +pub fn factorial(n: &u64) -> u64{ + match *n{ + 0 | 1 => 1, + _ => (1..=*n).product() + } +} + +pub fn factorial_checked(n: &u64) -> Option { + (1..=*n).try_fold(1u64, |acc, x| acc.checked_mul(x)) +} + +pub fn gcd(a: &i64, b: &i64) -> i64 { + let mut a: i64 = *a; + let mut b: i64 = *b; + + while b != 0 { + let t: i64 = b; + b = a % b; + a = t; + } + a.abs() +} + + +pub fn lcm(a: &i64, b: &i64) -> i64{ + let a: i64 = *a; + let b: i64 = *b; + + (a * b).abs() / gcd(&a, &b) +} + +pub fn comb(n: &u64, k: &u64) -> u64 { + let mut k: u64 = *k; + if k > *n { + return 0; + } + if k > *n - k { + k = *n - k; + } + (0..k).fold(1, |result, i| result * (n - i) / (i + 1)) +} + +pub fn perm(n: &u64, k: &u64) -> u64 { + if *k > *n { + return 0; + } + + let mut result = 1; + for i in 0..*k { + result *= *n - i; + } + result +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sqrt_positive(){ + assert_eq!(sqrt(&1.0), 1.0); + assert_eq!(sqrt(&4.0), 2.0); + assert_eq!(sqrt(&9.0), 3.0); + assert_eq!(sqrt(&25.0), 5.0); + assert_eq!(sqrt(&36.0), 6.0); + } + + #[test] + fn test_sqrt_zero(){ + assert_eq!(sqrt(&0.0), 0.0); + } + + #[test] + fn test_sqrt_negative(){ + assert!(sqrt(&-9.0).is_nan()); + } + + #[test] + fn test_factorial_base_cases() { + assert_eq!(factorial(&0), 1); + assert_eq!(factorial(&1), 1); + } + + #[test] + fn test_factorial_small_values(){ + assert_eq!(factorial(&2), 2); + assert_eq!(factorial(&3), 6); + assert_eq!(factorial(&4), 24); + assert_eq!(factorial(&5), 120); + assert_eq!(factorial(&6), 720); + } + + #[test] + fn test_factorial_medium_values(){ + assert_eq!(factorial(&9), 362_880); + assert_eq!(factorial(&10), 3_628_800); + } + + #[test] + fn test_factorial_maximum_value() { + assert_eq!(factorial(&20), 2_432_902_008_176_640_000); + assert!(factorial_checked(&21).is_none()); + } + + #[test] + fn test_gcd_with_zero() { + assert_eq!(gcd(&0, &0), 0); + assert_eq!(gcd(&15, &0), 15); + assert_eq!(gcd(&0, &79), 79); + assert_eq!(gcd(&0, &123_456), 123_456); + assert_eq!(gcd(&987_654, &0), 987_654); + } + + #[test] + fn test_gcd_large_values() { + assert_eq!(gcd(&1_000_000, &500_000), 500_000); + assert_eq!(gcd(&2_147_483_647, &1_073_741_824), 1); + } + + #[test] + fn test_gcd_general_cases() { + assert_eq!(gcd(&5, &7), 1); + assert_eq!(gcd(&100, &40), 20); + assert_eq!(gcd(&18, &90), 18); + assert_eq!(gcd(&18, &70), 2); + } + + #[test] + fn test_gcd_two_negatives() { + assert_eq!(gcd(&-54, &-9), 9); + assert_eq!(gcd(&-111, &-72), 3); + assert_eq!(gcd(&-37, &-54), 1); + assert_eq!(gcd(&-10, &-10), 10); + } + + #[test] + fn test_gcd_positive_negative() { + assert_eq!(gcd(&48, &-18), 6); + assert_eq!(gcd(&100, &-25), 25); + assert_eq!(gcd(&14, &-14), 14); + } + + #[test] + fn test_gcd_common_multiples() { + assert_eq!(gcd(&50, &25), 25); + assert_eq!(gcd(&81, &27), 27); + } + + #[test] + fn test_lcm_with_zero() { + assert_eq!(lcm(&5, &0), 0); + assert_eq!(lcm(&0, &7), 0); + } + + #[test] + fn test_lcm_general_cases() { + assert_eq!(lcm(&12, &18), 36); + assert_eq!(lcm(&4, &5), 20); + assert_eq!(lcm(&7, &3), 21); + } + + #[test] + fn test_lcm_positive_negative() { + assert_eq!(lcm(&12, &-18), 36); + assert_eq!(lcm(&-4, &5), 20); + assert_eq!(lcm(&-7, &3), 21); + } + #[test] + fn test_lcm_two_negatives() { + assert_eq!(lcm(&-12, &-18), 36); + assert_eq!(lcm(&-4, &-5), 20); + assert_eq!(lcm(&-7, &-3), 21); + } + + #[test] + fn test_lcm_large_values() { + assert_eq!(lcm(&1_000_000, &2_000_000), 2_000_000); + assert_eq!(lcm(&1_234_567, &2_345_678), 2_895_896_651_426); + } + + #[test] + fn test_lcm_common_multiples() { + assert_eq!(lcm(&50, &25), 50); + assert_eq!(lcm(&81, &27), 81); + } + + #[test] + fn test_comb_basic_cases() { + assert_eq!(comb(&5, &3), 10); + assert_eq!(comb(&5, &0), 1); + assert_eq!(comb(&0, &0), 1); + } + + #[test] + fn test_comb_large_values() { + assert_eq!(comb(&20, &10), 184_756); + assert_eq!(comb(&30, &15), 155_117_520); + } + + #[test] + fn test_comb_general_cases() { + assert_eq!(comb(&6, &2), 15); + assert_eq!(comb(&10, &5), 252); + assert_eq!(comb(&4, &4), 1); + } + + #[test] + fn test_perm_basic_cases() { + assert_eq!(perm(&5, &3), 60); + assert_eq!(perm(&5, &0), 1); + } + + #[test] + fn test_perm_large_values() { + assert_eq!(perm(&20, &5), 1_860_480); + assert_eq!(perm(&10, &10), 3_628_800); + } + + #[test] + fn test_perm_general_cases() { + assert_eq!(perm(&6, &2), 30); + assert_eq!(perm(&10, &3), 720); + assert_eq!(perm(&4, &4), 24); + } + +} \ No newline at end of file From 93a207d10a9b9078d50e8b4982b1d4e70dfd7a6f Mon Sep 17 00:00:00 2001 From: Layr Date: Fri, 14 Feb 2025 16:58:10 -0300 Subject: [PATCH 02/15] =?UTF-8?q?primeira=20implementa=C3=A7=C3=A3o=20do?= =?UTF-8?q?=20Meta?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/interpreter/interpreter.rs | 4 ++++ src/ir/ast.rs | 1 + src/tc/type_checker.rs | 3 +++ 3 files changed, 8 insertions(+) diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index bf3eab6..7e753b2 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -122,6 +122,10 @@ pub fn execute( let value = eval(*exp, &new_env)?; Ok(ControlFlow::Return(value)) } + Statement::MetaStmt(f) => { + f(&mut new_env)?; + Ok(ControlFlow::Continue(new_env)) + } _ => Err(String::from("not implemented yet")), } } diff --git a/src/ir/ast.rs b/src/ir/ast.rs index 4c56f94..c2a963c 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -74,6 +74,7 @@ pub enum Statement { Sequence(Box, Box), FuncDef(Name, Function), Return(Box), + MetaStmt(fn(&mut Environment) -> Result<(), String>), } #[derive(Debug)] diff --git a/src/tc/type_checker.rs b/src/tc/type_checker.rs index ccbeee4..d314da1 100644 --- a/src/tc/type_checker.rs +++ b/src/tc/type_checker.rs @@ -154,6 +154,9 @@ pub fn check_stmt( Ok(ControlType::Return(exp_type)) } + Statement::MetaStmt(_) =>{ + Ok(ControlType::Continue(env.clone())) + } _ => Err(String::from("not implemented yet")), } } From 852970b25b0de71a0681a672470e3c745e18c4c9 Mon Sep 17 00:00:00 2001 From: Layr Date: Fri, 14 Feb 2025 21:12:07 -0300 Subject: [PATCH 03/15] =?UTF-8?q?implementa=C3=A7=C3=A3o=20do=20Meta=20com?= =?UTF-8?q?=20vetor=20de=20Expression?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/interpreter/interpreter.rs | 84 ++++++++++++++++++++++++++++++++-- src/ir/ast.rs | 2 +- src/stdlib/math.rs | 69 +++++++++++++++++++++++----- src/tc/type_checker.rs | 2 +- 4 files changed, 140 insertions(+), 17 deletions(-) diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 7e753b2..ec3fa81 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -1,5 +1,6 @@ -use crate::ir::ast::{EnvValue, Environment, Expression, Name, Statement}; +use crate::ir::ast::{EnvValue, Environment, Expression, Name, Statement, Type}; use crate::tc::type_checker::{check_stmt, ControlType}; +use crate::stdlib::math::sqrt; use crate::HashMap; type ErrorMessage = String; @@ -122,14 +123,41 @@ pub fn execute( let value = eval(*exp, &new_env)?; Ok(ControlFlow::Return(value)) } - Statement::MetaStmt(f) => { - f(&mut new_env)?; + + Statement::MetaStmt(f, args_exprs) => { + let mut args_values = Vec::new(); + for expr in &args_exprs { + let env_value = eval(expr.clone(), &new_env)?; + args_values.push(env_value); + } + + + let result_value = f(args_values); + + + new_env.insert( + "result".to_string(), + (Some(result_value.clone()), get_type_env_value(&result_value)), + ); + Ok(ControlFlow::Continue(new_env)) } + _ => Err(String::from("not implemented yet")), } } +fn get_type_env_value(value: &EnvValue) -> Type { + match value { + EnvValue::Exp(Expression::CInt(_)) => Type::TInteger, + EnvValue::Exp(Expression::CReal(_)) => Type::TReal, + EnvValue::Exp(Expression::CString(_)) => Type::TString, + EnvValue::Exp(Expression::CTrue) | EnvValue::Exp(Expression::CFalse) => Type::TBool, + EnvValue::Func(_) => Type::TFunction, + _ => unreachable!(), + } +} + fn call(name: Name, args: Vec, env: &Environment) -> Result { match env.get(&name) { Some((Some(EnvValue::Func(func)), _)) => { @@ -994,4 +1022,54 @@ mod tests { Err(s) => assert!(false, "{}", s), } } + + #[test] + fn test_metastmt_sqrt_in_interpreter() { + // Cria um ambiente inicial + let mut env = Environment::new(); + + // Insere a variável 'x' com o valor 9.0 no ambiente + env.insert( + "x".to_string(), + ( + Some(EnvValue::Exp(Expression::CReal(9.0))), + Type::TReal, + ), + ); + + // Cria o MetaStmt que chama a função sqrt_env com 'x' como argumento + let meta_stmt = Statement::MetaStmt( + sqrt, + vec![Expression::Var("x".to_string())], + ); + + // Programa que executa o MetaStmt e armazena o resultado em 'result' + let program = Sequence( + Box::new(meta_stmt), + Box::new(Assignment( + "x".to_string(), + Box::new(Var("result".to_string())), // Atribui o resultado de volta a 'x' + Some(Type::TReal), + )), + ); + + // Executa o programa + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + // Verifica se 'result' contém o valor 3.0 + assert_eq!( + new_env.get("x"), + Some(&( + Some(EnvValue::Exp(Expression::CReal(3.0))), + Type::TReal, + )) + ); + println!("Resultado: {}", 3.0); // Deve imprimir: Resultado: 3.0 + }, + Ok(_) => panic!("Programa não continuou a execução corretamente"), + Err(err) => panic!("Erro durante a execução: {}", err), + } + } + + } diff --git a/src/ir/ast.rs b/src/ir/ast.rs index c2a963c..61ecc7b 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -74,7 +74,7 @@ pub enum Statement { Sequence(Box, Box), FuncDef(Name, Function), Return(Box), - MetaStmt(fn(&mut Environment) -> Result<(), String>), + MetaStmt(fn(Vec) -> EnvValue, Vec), } #[derive(Debug)] diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs index b4c89ff..d14df86 100644 --- a/src/stdlib/math.rs +++ b/src/stdlib/math.rs @@ -1,5 +1,11 @@ -pub fn sqrt(x: &f64) -> f64 { - x.sqrt() +use crate::ir::ast::{EnvValue, Expression}; + +pub fn sqrt(args: Vec) -> EnvValue { + if let EnvValue::Exp(Expression::CReal(x)) = &args[0] { + EnvValue::Exp(Expression::CReal(x.sqrt())) + } else { + EnvValue::Exp(Expression::CReal(f64::NAN)) + } } pub fn factorial(n: &u64) -> u64{ @@ -61,24 +67,63 @@ mod tests { use super::*; #[test] - fn test_sqrt_positive(){ - assert_eq!(sqrt(&1.0), 1.0); - assert_eq!(sqrt(&4.0), 2.0); - assert_eq!(sqrt(&9.0), 3.0); - assert_eq!(sqrt(&25.0), 5.0); - assert_eq!(sqrt(&36.0), 6.0); + fn test_sqrt_positive_real() { + let args = vec![EnvValue::Exp(Expression::CReal(9.0))]; + let result = sqrt(args); + + if let EnvValue::Exp(Expression::CReal(res_value)) = result { + assert_eq!(res_value, 3.0); + } else { + panic!("O resultado não é um número real"); + } + } + + #[test] + fn test_sqrt_zero() { + let args = vec![EnvValue::Exp(Expression::CReal(0.0))]; + let result = sqrt(args); + + if let EnvValue::Exp(Expression::CReal(res_value)) = result { + assert_eq!(res_value, 0.0); + } else { + panic!("O resultado não é um número real"); + } + } + + #[test] + fn test_sqrt_negative_real() { + let args = vec![EnvValue::Exp(Expression::CReal(-4.0))]; + let result = sqrt(args); + + if let EnvValue::Exp(Expression::CReal(res_value)) = result { + assert!(res_value.is_nan(), "O resultado deveria ser NaN para números negativos"); + } else { + panic!("O resultado não é um número real"); + } } #[test] - fn test_sqrt_zero(){ - assert_eq!(sqrt(&0.0), 0.0); + fn test_sqrt_invalid_argument() { + let args = vec![EnvValue::Exp(Expression::CString("invalid".to_string()))]; + + let result = sqrt(args); + + if let EnvValue::Exp(Expression::CReal(res_value)) = result { + assert!(res_value.is_nan(), "O resultado deveria ser NaN para argumentos inválidos"); + } else { + panic!("O resultado não é um número real"); + } } #[test] - fn test_sqrt_negative(){ - assert!(sqrt(&-9.0).is_nan()); + #[should_panic(expected = "index out of bounds")] + fn test_sqrt_no_arguments() { + let args = vec![]; + + let _ = sqrt(args); } + #[test] fn test_factorial_base_cases() { assert_eq!(factorial(&0), 1); diff --git a/src/tc/type_checker.rs b/src/tc/type_checker.rs index d314da1..4ee9954 100644 --- a/src/tc/type_checker.rs +++ b/src/tc/type_checker.rs @@ -154,7 +154,7 @@ pub fn check_stmt( Ok(ControlType::Return(exp_type)) } - Statement::MetaStmt(_) =>{ + Statement::MetaStmt(_, _) =>{ Ok(ControlType::Continue(env.clone())) } _ => Err(String::from("not implemented yet")), From de0eb9a2d6770abb64e958ca91f2bb9d9bfe8ca2 Mon Sep 17 00:00:00 2001 From: Layr Date: Sat, 15 Feb 2025 11:35:14 -0300 Subject: [PATCH 04/15] meta com tipo de retorno --- src/interpreter/interpreter.rs | 157 +++++++++++++++++++++++---------- src/ir/ast.rs | 2 +- src/tc/type_checker.rs | 95 +++++++++++++++++++- 3 files changed, 205 insertions(+), 49 deletions(-) diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index ec3fa81..a52c69c 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -1,6 +1,5 @@ -use crate::ir::ast::{EnvValue, Environment, Expression, Name, Statement, Type}; +use crate::ir::ast::{EnvValue, Environment, Expression, Name, Statement}; use crate::tc::type_checker::{check_stmt, ControlType}; -use crate::stdlib::math::sqrt; use crate::HashMap; type ErrorMessage = String; @@ -124,7 +123,7 @@ pub fn execute( Ok(ControlFlow::Return(value)) } - Statement::MetaStmt(f, args_exprs) => { + Statement::MetaStmt(f, args_exprs, return_type) => { let mut args_values = Vec::new(); for expr in &args_exprs { let env_value = eval(expr.clone(), &new_env)?; @@ -136,8 +135,8 @@ pub fn execute( new_env.insert( - "result".to_string(), - (Some(result_value.clone()), get_type_env_value(&result_value)), + "metaResult".to_string(), + (Some(result_value.clone()), return_type.clone()), ); Ok(ControlFlow::Continue(new_env)) @@ -147,17 +146,6 @@ pub fn execute( } } -fn get_type_env_value(value: &EnvValue) -> Type { - match value { - EnvValue::Exp(Expression::CInt(_)) => Type::TInteger, - EnvValue::Exp(Expression::CReal(_)) => Type::TReal, - EnvValue::Exp(Expression::CString(_)) => Type::TString, - EnvValue::Exp(Expression::CTrue) | EnvValue::Exp(Expression::CFalse) => Type::TBool, - EnvValue::Func(_) => Type::TFunction, - _ => unreachable!(), - } -} - fn call(name: Name, args: Vec, env: &Environment) -> Result { match env.get(&name) { Some((Some(EnvValue::Func(func)), _)) => { @@ -466,6 +454,7 @@ mod tests { use crate::ir::ast::Function; use crate::ir::ast::Statement::*; use crate::ir::ast::Type::*; + use crate::stdlib::math::sqrt; use approx::relative_eq; #[test] @@ -1023,51 +1012,129 @@ mod tests { } } + #[test] - fn test_metastmt_sqrt_in_interpreter() { - // Cria um ambiente inicial - let mut env = Environment::new(); + fn metastmt_sqrt() { + /* + * Teste para a função de raiz quadrada (sqrt) usando MetaStmt + * + * Código rpy imaginário: + * + * > x: TReal = 16.0 + * > MetaStmt(sqrt, [x]) + * > resultado: TReal = metaResult + * + * Após a execução, 'result' deve ser 4.0 (sqrt(16.0) = 4.0). + */ + + let env = Environment::new(); - // Insere a variável 'x' com o valor 9.0 no ambiente - env.insert( + let assign_x = Statement::Assignment( "x".to_string(), - ( - Some(EnvValue::Exp(Expression::CReal(9.0))), - Type::TReal, - ), + Box::new(Expression::CReal(16.0)), + Some(TReal), ); - // Cria o MetaStmt que chama a função sqrt_env com 'x' como argumento let meta_stmt = Statement::MetaStmt( sqrt, vec![Expression::Var("x".to_string())], + TReal ); - // Programa que executa o MetaStmt e armazena o resultado em 'result' - let program = Sequence( - Box::new(meta_stmt), - Box::new(Assignment( - "x".to_string(), - Box::new(Var("result".to_string())), // Atribui o resultado de volta a 'x' - Some(Type::TReal), + let assign_result = Statement::Assignment( + "resultado".to_string(), + Box::new(Expression::Var("metaResult".to_string())), + Some(TReal), + ); + + let program = Statement::Sequence( + Box::new(assign_x), + Box::new(Statement::Sequence( + Box::new(meta_stmt), + Box::new(assign_result), )), ); - // Executa o programa match execute(program, &env, true) { Ok(ControlFlow::Continue(new_env)) => { - // Verifica se 'result' contém o valor 3.0 - assert_eq!( - new_env.get("x"), - Some(&( - Some(EnvValue::Exp(Expression::CReal(3.0))), - Type::TReal, + if let Some(&(Some(EnvValue::Exp(Expression::CReal(value))), _)) = new_env.get("metaResult") { + assert_eq!(value, 4.0); + } else { + panic!("Variável 'result' não encontrada ou tem tipo incorreto"); + } + } + Ok(_) => panic!("O interpretador não continuou a execução como esperado"), + Err(err) => panic!("Falha na execução do interpretador com erro: {}", err), + } + } + + #[test] + fn metastmt_function_sqrt() { + /* + * Teste para a função de raiz quadrada (sqrt) usando MetaStmt + * + * Código rpy imaginário: + * + * > x: TReal = 25.0 + * > def sqrt(x: TReal) -> TReal: + * > MetaStmt(sqrt, [x]) + * > return metaResult + * > x = sqrt(x) + * + * Após a execução, 'x' deve ser 5.0 (sqrt(25.0) = 5.0). + */ + let env = Environment::new(); + + let assign_x = Statement::Assignment( + "x".to_string(), + Box::new(Expression::CReal(25.0)), + Some(TReal), + ); + + let meta_stmt = Statement::MetaStmt( + sqrt, + vec![Expression::Var("x".to_string())], + TReal + ); + + let func: Statement = FuncDef( + "sqrt".to_string(), + Function { + kind: TReal, + params: Some(vec![("x".to_string(), TReal)]), + body: Box::new(Sequence( + Box::new(meta_stmt), + Box::new(Return( + Box::new(Expression::Var("metaResult".to_string())) )) - ); - println!("Resultado: {}", 3.0); // Deve imprimir: Resultado: 3.0 - }, - Ok(_) => panic!("Programa não continuou a execução corretamente"), - Err(err) => panic!("Erro durante a execução: {}", err), + )) + } + ); + + let assign_result = Statement::Assignment( + "x".to_string(), + Box::new(Expression::FuncCall("sqrt".to_string(), vec![Expression::Var("x".to_string())])), + Some(TReal), + ); + + let program = Statement::Sequence( + Box::new(assign_x), + Box::new(Statement::Sequence( + Box::new(func), + Box::new(assign_result), + )), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some(&(Some(EnvValue::Exp(Expression::CReal(value))), _)) = new_env.get("x") { + assert_eq!(value, 5.0); + } else { + panic!("Variável 'x' não encontrada ou tem tipo incorreto"); + } + } + Ok(_) => panic!("O interpretador não continuou a execução como esperado"), + Err(err) => panic!("Falha na execução do interpretador com erro: {}", err), } } diff --git a/src/ir/ast.rs b/src/ir/ast.rs index 61ecc7b..d39b910 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -74,7 +74,7 @@ pub enum Statement { Sequence(Box, Box), FuncDef(Name, Function), Return(Box), - MetaStmt(fn(Vec) -> EnvValue, Vec), + MetaStmt(fn(Vec) -> EnvValue, Vec, Type), } #[derive(Debug)] diff --git a/src/tc/type_checker.rs b/src/tc/type_checker.rs index 4ee9954..a3c7d26 100644 --- a/src/tc/type_checker.rs +++ b/src/tc/type_checker.rs @@ -154,9 +154,20 @@ pub fn check_stmt( Ok(ControlType::Return(exp_type)) } - Statement::MetaStmt(_, _) =>{ - Ok(ControlType::Continue(env.clone())) - } + + Statement::MetaStmt(_f, args, return_type) => { + for arg in args { + check_exp(arg.clone(), env)?; + } + + let mut new_env = env.clone(); + new_env.insert( + "metaResult".to_string(), + (Some(EnvValue::Exp(Expression::Var("result".to_string()))), return_type.clone()) + ); + Ok(ControlType::Continue(new_env)) + } + _ => Err(String::from("not implemented yet")), } } @@ -271,6 +282,7 @@ mod tests { use crate::ir::ast::Function; use crate::ir::ast::Statement::*; use crate::ir::ast::Type::*; + use crate::stdlib::math::sqrt; #[test] fn check_tlist_comparison() { @@ -786,4 +798,81 @@ mod tests { Err(s) => assert_eq!(s, "[Type Error] 'func()' is not defined."), } } + + #[test] + fn check_metastmt_valid() { + let mut env = Environment::new(); + env.insert( + "x".to_string(), + ( + Some(EnvValue::Exp(Expression::CReal(9.0))), + Type::TReal, + ), + ); + + let meta_stmt = Statement::MetaStmt( + sqrt, + vec![Expression::Var("x".to_string())], + Type::TReal, + ); + + let assign_stmt = Statement::Assignment( + "resultado".to_string(), + Box::new(Expression::Var("metaResult".to_string())), + Some(Type::TReal), + ); + + let program = Statement::Sequence( + Box::new(meta_stmt), + Box::new(assign_stmt), + ); + + match check_stmt(program, &env, None) { + Ok(ControlType::Continue(new_env)) => { + let meta_result_type = new_env + .get("metaResult") + .expect("metaResult não foi definido no ambiente") + .1 + .clone(); + assert_eq!(meta_result_type, Type::TReal); + } + Ok(_) => panic!("O type checker não retornou um fluxo de controle esperado"), + Err(err) => panic!("Type checker falhou com erro: {}", err), + } + } + + #[test] + fn check_metastmt_invalid_assignment() { + let mut env = Environment::new(); + env.insert( + "x".to_string(), + ( + Some(EnvValue::Exp(Expression::CReal(16.0))), + Type::TReal, + ), + ); + + let meta_stmt = Statement::MetaStmt( + sqrt, + vec![Expression::Var("x".to_string())], + Type::TReal, + ); + + let assign_stmt = Statement::Assignment( + "resultado".to_string(), + Box::new(Expression::Var("metaResult".to_string())), + Some(Type::TBool), + ); + + let program = Statement::Sequence( + Box::new(meta_stmt), + Box::new(assign_stmt), + ); + + match check_stmt(program, &env, None) { + Err(_err) => (), + Ok(_) => panic!("Type checker deveria ter falhado devido à incompatibilidade de tipos"), + } + } + } From d609500cef402f896ca6955aa6c7e26f1a7063c2 Mon Sep 17 00:00:00 2001 From: Layr Date: Sat, 15 Feb 2025 13:05:36 -0300 Subject: [PATCH 05/15] Math adpatada pra ser usada pelo MetaStmt --- src/interpreter/interpreter.rs | 112 ++++++-- src/stdlib/math.rs | 476 ++++++++++++++++++++++----------- src/tc/type_checker.rs | 12 +- 3 files changed, 416 insertions(+), 184 deletions(-) diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index a52c69c..14a69a9 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -454,7 +454,7 @@ mod tests { use crate::ir::ast::Function; use crate::ir::ast::Statement::*; use crate::ir::ast::Type::*; - use crate::stdlib::math::sqrt; + use crate::stdlib::math::{sqrt, gcd}; use approx::relative_eq; #[test] @@ -1016,15 +1016,15 @@ mod tests { #[test] fn metastmt_sqrt() { /* - * Teste para a função de raiz quadrada (sqrt) usando MetaStmt + * Test for the square root function (sqrt) using MetaStmt * - * Código rpy imaginário: + * Imaginary rpy code: * * > x: TReal = 16.0 * > MetaStmt(sqrt, [x]) - * > resultado: TReal = metaResult + * > result: TReal = metaResult * - * Após a execução, 'result' deve ser 4.0 (sqrt(16.0) = 4.0). + * After execution, 'result' should be 4.0 (sqrt(16.0) = 4.0). */ let env = Environment::new(); @@ -1042,7 +1042,7 @@ mod tests { ); let assign_result = Statement::Assignment( - "resultado".to_string(), + "result".to_string(), Box::new(Expression::Var("metaResult".to_string())), Some(TReal), ); @@ -1060,20 +1060,20 @@ mod tests { if let Some(&(Some(EnvValue::Exp(Expression::CReal(value))), _)) = new_env.get("metaResult") { assert_eq!(value, 4.0); } else { - panic!("Variável 'result' não encontrada ou tem tipo incorreto"); + panic!("Variable 'metaResult' not found or has incorrect type"); } } - Ok(_) => panic!("O interpretador não continuou a execução como esperado"), - Err(err) => panic!("Falha na execução do interpretador com erro: {}", err), + Ok(_) => panic!("The interpreter did not continue execution as expected"), + Err(err) => panic!("Interpreter execution failed with error: {}", err), } } #[test] fn metastmt_function_sqrt() { /* - * Teste para a função de raiz quadrada (sqrt) usando MetaStmt + * Test for the r-python square root function (sqrt) using MetaStmt * - * Código rpy imaginário: + * Imaginary rpy code: * * > x: TReal = 25.0 * > def sqrt(x: TReal) -> TReal: @@ -1081,7 +1081,7 @@ mod tests { * > return metaResult * > x = sqrt(x) * - * Após a execução, 'x' deve ser 5.0 (sqrt(25.0) = 5.0). + * After execution, 'x' should be 5.0 (sqrt(25.0) = 5.0). */ let env = Environment::new(); @@ -1130,13 +1130,93 @@ mod tests { if let Some(&(Some(EnvValue::Exp(Expression::CReal(value))), _)) = new_env.get("x") { assert_eq!(value, 5.0); } else { - panic!("Variável 'x' não encontrada ou tem tipo incorreto"); + panic!("Variable 'x' not found or has incorrect type"); } } - Ok(_) => panic!("O interpretador não continuou a execução como esperado"), - Err(err) => panic!("Falha na execução do interpretador com erro: {}", err), + Ok(_) => panic!("The interpreter did not continue execution as expected"), + Err(err) => panic!("Interpreter execution failed with error: {}", err), } } - + #[test] + fn metastmt_function_gcd() { + /* + * Test for the greatest common divisor function (gcd) using MetaStmt + * + * Imaginary rpy code: + * + * > a: TInteger = 48 + * > b: TInteger = 18 + * > def gcd(a: TInteger, b: TInteger) -> TInteger: + * > MetaStmt(gcd, [a, b]) + * > return metaResult + * > result = gcd(a, b) + * + * After execution, 'result' should be 6 (gcd(48, 18) = 6). + */ + + let env = Environment::new(); + + let assign_a = Statement::Assignment( + "a".to_string(), + Box::new(Expression::CInt(48)), + Some(TInteger), + ); + + let assign_b = Statement::Assignment( + "b".to_string(), + Box::new(Expression::CInt(18)), + Some(TInteger), + ); + + let meta_stmt = Statement::MetaStmt( + gcd, + vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], + TInteger, + ); + + let func: Statement = Statement::FuncDef( + "gcd".to_string(), + Function { + kind: TInteger, + params: Some(vec![("a".to_string(), TInteger), ("b".to_string(), TInteger)]), + body: Box::new(Statement::Sequence( + Box::new(meta_stmt), + Box::new(Statement::Return( + Box::new(Expression::Var("metaResult".to_string())) + )), + )), + }, + ); + + let assign_result = Statement::Assignment( + "result".to_string(), + Box::new(Expression::FuncCall("gcd".to_string(), vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())])), + Some(TInteger), + ); + + let program = Statement::Sequence( + Box::new(assign_a), + Box::new(Statement::Sequence( + Box::new(assign_b), + Box::new(Statement::Sequence( + Box::new(func), + Box::new(assign_result), + )), + )), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some(&(Some(EnvValue::Exp(Expression::CInt(value))), _)) = new_env.get("result") { + assert_eq!(value, 6); + } else { + panic!("Variable 'result' not found or has incorrect type"); + } + } + Ok(_) => panic!("The interpreter did not continue execution as expected"), + Err(err) => panic!("Interpreter execution failed with error: {}", err), + } + } + } diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs index d14df86..58e92d3 100644 --- a/src/stdlib/math.rs +++ b/src/stdlib/math.rs @@ -1,65 +1,120 @@ use crate::ir::ast::{EnvValue, Expression}; pub fn sqrt(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("sqrt expects exactly one argument"); + } + if let EnvValue::Exp(Expression::CReal(x)) = &args[0] { EnvValue::Exp(Expression::CReal(x.sqrt())) } else { - EnvValue::Exp(Expression::CReal(f64::NAN)) + panic!("sqrt expects a real number argument"); } } -pub fn factorial(n: &u64) -> u64{ - match *n{ - 0 | 1 => 1, - _ => (1..=*n).product() - } -} -pub fn factorial_checked(n: &u64) -> Option { - (1..=*n).try_fold(1u64, |acc, x| acc.checked_mul(x)) +pub fn factorial(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("factorial expects exactly one argument"); + } + if let EnvValue::Exp(Expression::CInt(n)) = &args[0] { + if *n < 0 { + panic!("factorial expects a non-negative integer argument"); + } + let mut prod: i32 = 1; + for i in 1..=*n { + prod *= i; + } + EnvValue::Exp(Expression::CInt(prod)) + } else { + panic!("factorial expects a integer argument"); + } } -pub fn gcd(a: &i64, b: &i64) -> i64 { - let mut a: i64 = *a; - let mut b: i64 = *b; - while b != 0 { - let t: i64 = b; - b = a % b; - a = t; +pub fn gcd(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("gcd expects exactly two arguments"); + } + if let (EnvValue::Exp(Expression::CInt(a)), EnvValue::Exp(Expression::CInt(b))) = + (&args[0], &args[1]) + { + let mut a = *a; + let mut b = *b; + while b != 0 { + let t = b; + b = a % b; + a = t; + } + EnvValue::Exp(Expression::CInt(a.abs())) + } else { + panic!("gcd expects two integer arguments"); } - a.abs() } - -pub fn lcm(a: &i64, b: &i64) -> i64{ - let a: i64 = *a; - let b: i64 = *b; - - (a * b).abs() / gcd(&a, &b) +pub fn lcm(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("lcm expects exactly two arguments"); + } + if let (EnvValue::Exp(Expression::CInt(a)), EnvValue::Exp(Expression::CInt(b))) = + (&args[0], &args[1]) + { + let gcd_val = match gcd(args.clone()) { + EnvValue::Exp(Expression::CInt(val)) => val, + _ => panic!("Error calculating gcd"), + }; + + let lcm_val = (a * b).abs() / gcd_val; + EnvValue::Exp(Expression::CInt(lcm_val)) + } else { + panic!("lcm expects two integer arguments"); + } } -pub fn comb(n: &u64, k: &u64) -> u64 { - let mut k: u64 = *k; - if k > *n { - return 0; +pub fn comb(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("comb expects exactly two arguments"); } - if k > *n - k { - k = *n - k; + if let (EnvValue::Exp(Expression::CInt(n)), EnvValue::Exp(Expression::CInt(k))) = (&args[0], &args[1]) { + if *n < 0 || *k < 0 { + panic!("comb expects non-negative integers"); + } + let n = *n; + let mut k = *k; + if k > n { + return EnvValue::Exp(Expression::CInt(0)); + } + if k > n - k { + k = n - k; + } + let result = (0..k).fold(1, |acc, i| acc * (n - i) / (i + 1)); + EnvValue::Exp(Expression::CInt(result)) + } else { + panic!("comb expects two integer arguments"); } - (0..k).fold(1, |result, i| result * (n - i) / (i + 1)) } -pub fn perm(n: &u64, k: &u64) -> u64 { - if *k > *n { - return 0; +pub fn perm(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("perm expects exactly two arguments"); } - - let mut result = 1; - for i in 0..*k { - result *= *n - i; + if let (EnvValue::Exp(Expression::CInt(n)), EnvValue::Exp(Expression::CInt(k))) = (&args[0], &args[1]) { + if *n < 0 || *k < 0 { + panic!("perm expects non-negative integers"); + } + let n = *n; + let k = *k; + if k > n { + return EnvValue::Exp(Expression::CInt(0)); + } + let mut result: i32 = 1; + for i in 0..k { + result *= n - i; + } + EnvValue::Exp(Expression::CInt(result)) + } else { + panic!("perm expects two integer arguments"); } - result } #[cfg(test)] @@ -68,208 +123,305 @@ mod tests { #[test] fn test_sqrt_positive_real() { - let args = vec![EnvValue::Exp(Expression::CReal(9.0))]; - let result = sqrt(args); + let result = sqrt(vec![EnvValue::Exp(Expression::CReal(9.0))]); + match result { + EnvValue::Exp(Expression::CReal(res_value)) => assert_eq!(res_value, 3.0), + _ => panic!("Incorrect result for sqrt of 9.0"), + } + + let result = sqrt(vec![EnvValue::Exp(Expression::CReal(49.0))]); + match result { + EnvValue::Exp(Expression::CReal(res_value)) => assert_eq!(res_value, 7.0), + _ => panic!("Incorrect result for sqrt of 49.0"), + } - if let EnvValue::Exp(Expression::CReal(res_value)) = result { - assert_eq!(res_value, 3.0); - } else { - panic!("O resultado não é um número real"); + let result = sqrt(vec![EnvValue::Exp(Expression::CReal(121.0))]); + match result { + EnvValue::Exp(Expression::CReal(res_value)) => assert_eq!(res_value, 11.0), + _ => panic!("Incorrect result for sqrt of 121.0"), } } #[test] fn test_sqrt_zero() { - let args = vec![EnvValue::Exp(Expression::CReal(0.0))]; - let result = sqrt(args); - - if let EnvValue::Exp(Expression::CReal(res_value)) = result { - assert_eq!(res_value, 0.0); - } else { - panic!("O resultado não é um número real"); + let result = sqrt(vec![EnvValue::Exp(Expression::CReal(0.0))]); + match result { + EnvValue::Exp(Expression::CReal(res_value)) => assert_eq!(res_value, 0.0), + _ => panic!("Incorrect result for sqrt of 0.0"), } } #[test] - fn test_sqrt_negative_real() { - let args = vec![EnvValue::Exp(Expression::CReal(-4.0))]; - let result = sqrt(args); - - if let EnvValue::Exp(Expression::CReal(res_value)) = result { - assert!(res_value.is_nan(), "O resultado deveria ser NaN para números negativos"); - } else { - panic!("O resultado não é um número real"); - } + #[should_panic(expected = "sqrt expects exactly one argument")] + fn test_sqrt_invalid_number_of_arguments() { + sqrt(vec![]); } #[test] - fn test_sqrt_invalid_argument() { - let args = vec![EnvValue::Exp(Expression::CString("invalid".to_string()))]; - - let result = sqrt(args); - - if let EnvValue::Exp(Expression::CReal(res_value)) = result { - assert!(res_value.is_nan(), "O resultado deveria ser NaN para argumentos inválidos"); - } else { - panic!("O resultado não é um número real"); - } + #[should_panic(expected = "sqrt expects exactly one argument")] + fn test_sqrt_invalid_number_of_arguments_multiple() { + sqrt(vec![ + EnvValue::Exp(Expression::CReal(25.0)), + EnvValue::Exp(Expression::CReal(9.0)), + ]); } #[test] - #[should_panic(expected = "index out of bounds")] - fn test_sqrt_no_arguments() { - let args = vec![]; - - let _ = sqrt(args); + #[should_panic(expected = "sqrt expects a real number argument")] + fn test_sqrt_invalid_argument_type() { + sqrt(vec![EnvValue::Exp(Expression::CInt(25))]); } - - + +//==================================================================================================== #[test] - fn test_factorial_base_cases() { - assert_eq!(factorial(&0), 1); - assert_eq!(factorial(&1), 1); + fn test_factorial_valid_inputs() { + let result = factorial(vec![EnvValue::Exp(Expression::CInt(0))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 1), + _ => panic!("Incorrect result for factorial of 0"), + } + + let result = factorial(vec![EnvValue::Exp(Expression::CInt(1))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 1), + _ => panic!("Incorrect result for factorial of 1"), + } + + let result = factorial(vec![EnvValue::Exp(Expression::CInt(5))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 120), + _ => panic!("Incorrect result for factorial of 5"), + } + + let result = factorial(vec![EnvValue::Exp(Expression::CInt(10))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 3628800), + _ => panic!("Incorrect result for factorial of 10"), + } } #[test] - fn test_factorial_small_values(){ - assert_eq!(factorial(&2), 2); - assert_eq!(factorial(&3), 6); - assert_eq!(factorial(&4), 24); - assert_eq!(factorial(&5), 120); - assert_eq!(factorial(&6), 720); + #[should_panic(expected = "factorial expects exactly one argument")] + fn test_factorial_invalid_number_of_arguments() { + factorial(vec![]); } #[test] - fn test_factorial_medium_values(){ - assert_eq!(factorial(&9), 362_880); - assert_eq!(factorial(&10), 3_628_800); + #[should_panic(expected = "factorial expects exactly one argument")] + fn test_factorial_invalid_number_of_arguments_multiple() { + factorial(vec![EnvValue::Exp(Expression::CInt(1)), EnvValue::Exp(Expression::CInt(2))]); } #[test] - fn test_factorial_maximum_value() { - assert_eq!(factorial(&20), 2_432_902_008_176_640_000); - assert!(factorial_checked(&21).is_none()); + #[should_panic(expected = "factorial expects a integer argument")] + fn test_factorial_invalid_argument_type() { + factorial(vec![EnvValue::Exp(Expression::CReal(3.5))]); } #[test] - fn test_gcd_with_zero() { - assert_eq!(gcd(&0, &0), 0); - assert_eq!(gcd(&15, &0), 15); - assert_eq!(gcd(&0, &79), 79); - assert_eq!(gcd(&0, &123_456), 123_456); - assert_eq!(gcd(&987_654, &0), 987_654); + #[should_panic(expected = "factorial expects a non-negative integer argument")] + fn test_factorial_negative_argument() { + factorial(vec![EnvValue::Exp(Expression::CInt(-1))]); } +//==================================================================================================== #[test] - fn test_gcd_large_values() { - assert_eq!(gcd(&1_000_000, &500_000), 500_000); - assert_eq!(gcd(&2_147_483_647, &1_073_741_824), 1); + fn test_gcd_valid_inputs() { + let result = gcd(vec![EnvValue::Exp(Expression::CInt(48)), EnvValue::Exp(Expression::CInt(18))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 6), + _ => panic!("Incorrect result for gcd of 48 and 18"), + } + + let result = gcd(vec![EnvValue::Exp(Expression::CInt(7)), EnvValue::Exp(Expression::CInt(3))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 1), + _ => panic!("Incorrect result for gcd of 7 and 3"), + } + + let result = gcd(vec![EnvValue::Exp(Expression::CInt(-48)), EnvValue::Exp(Expression::CInt(18))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 6), + _ => panic!("Incorrect result for gcd of -48 and 18"), + } + + let result = gcd(vec![EnvValue::Exp(Expression::CInt(0)), EnvValue::Exp(Expression::CInt(18))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 18), + _ => panic!("Incorrect result for gcd of 0 and 18"), + } } #[test] - fn test_gcd_general_cases() { - assert_eq!(gcd(&5, &7), 1); - assert_eq!(gcd(&100, &40), 20); - assert_eq!(gcd(&18, &90), 18); - assert_eq!(gcd(&18, &70), 2); + #[should_panic(expected = "gcd expects exactly two arguments")] + fn test_gcd_invalid_number_of_arguments() { + gcd(vec![EnvValue::Exp(Expression::CInt(48))]); } #[test] - fn test_gcd_two_negatives() { - assert_eq!(gcd(&-54, &-9), 9); - assert_eq!(gcd(&-111, &-72), 3); - assert_eq!(gcd(&-37, &-54), 1); - assert_eq!(gcd(&-10, &-10), 10); + #[should_panic(expected = "gcd expects exactly two arguments")] + fn test_gcd_invalid_number_of_arguments_multiple() { + gcd(vec![ + EnvValue::Exp(Expression::CInt(48)), + EnvValue::Exp(Expression::CInt(18)), + EnvValue::Exp(Expression::CInt(6)), + ]); } #[test] - fn test_gcd_positive_negative() { - assert_eq!(gcd(&48, &-18), 6); - assert_eq!(gcd(&100, &-25), 25); - assert_eq!(gcd(&14, &-14), 14); + #[should_panic(expected = "gcd expects two integer arguments")] + fn test_gcd_invalid_argument_type() { + gcd(vec![EnvValue::Exp(Expression::CReal(48.0)), EnvValue::Exp(Expression::CInt(18))]); } - + +//==================================================================================================== #[test] - fn test_gcd_common_multiples() { - assert_eq!(gcd(&50, &25), 25); - assert_eq!(gcd(&81, &27), 27); + fn test_lcm_valid_inputs() { + let result = lcm(vec![EnvValue::Exp(Expression::CInt(48)), EnvValue::Exp(Expression::CInt(18))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 144), + _ => panic!("Incorrect result for lcm of 48 and 18"), + } + + let result = lcm(vec![EnvValue::Exp(Expression::CInt(7)), EnvValue::Exp(Expression::CInt(3))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 21), + _ => panic!("Incorrect result for lcm of 7 and 3"), + } + + let result = lcm(vec![EnvValue::Exp(Expression::CInt(-48)), EnvValue::Exp(Expression::CInt(18))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 144), + _ => panic!("Incorrect result for lcm of -48 and 18"), + } + + let result = lcm(vec![EnvValue::Exp(Expression::CInt(0)), EnvValue::Exp(Expression::CInt(18))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 0), + _ => panic!("Incorrect result for lcm of 0 and 18"), + } } #[test] - fn test_lcm_with_zero() { - assert_eq!(lcm(&5, &0), 0); - assert_eq!(lcm(&0, &7), 0); + #[should_panic(expected = "lcm expects exactly two arguments")] + fn test_lcm_invalid_number_of_arguments() { + lcm(vec![EnvValue::Exp(Expression::CInt(48))]); } #[test] - fn test_lcm_general_cases() { - assert_eq!(lcm(&12, &18), 36); - assert_eq!(lcm(&4, &5), 20); - assert_eq!(lcm(&7, &3), 21); + #[should_panic(expected = "lcm expects exactly two arguments")] + fn test_lcm_invalid_number_of_arguments_multiple() { + lcm(vec![ + EnvValue::Exp(Expression::CInt(48)), + EnvValue::Exp(Expression::CInt(18)), + EnvValue::Exp(Expression::CInt(6)), + ]); } #[test] - fn test_lcm_positive_negative() { - assert_eq!(lcm(&12, &-18), 36); - assert_eq!(lcm(&-4, &5), 20); - assert_eq!(lcm(&-7, &3), 21); + #[should_panic(expected = "lcm expects two integer arguments")] + fn test_lcm_invalid_argument_type() { + lcm(vec![EnvValue::Exp(Expression::CReal(48.0)), EnvValue::Exp(Expression::CInt(18))]); + } + +//==================================================================================================== #[test] - fn test_lcm_two_negatives() { - assert_eq!(lcm(&-12, &-18), 36); - assert_eq!(lcm(&-4, &-5), 20); - assert_eq!(lcm(&-7, &-3), 21); + fn test_comb_valid_inputs() { + let result = comb(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(2))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 10), + _ => panic!("Incorrect result for comb(5, 2)"), + } + + let result = comb(vec![EnvValue::Exp(Expression::CInt(10)), EnvValue::Exp(Expression::CInt(3))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 120), + _ => panic!("Incorrect result for comb(10, 3)"), + } + + let result = comb(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(6))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 0), + _ => panic!("Incorrect result for comb(5, 6)"), + } } #[test] - fn test_lcm_large_values() { - assert_eq!(lcm(&1_000_000, &2_000_000), 2_000_000); - assert_eq!(lcm(&1_234_567, &2_345_678), 2_895_896_651_426); + #[should_panic(expected = "comb expects exactly two arguments")] + fn test_comb_invalid_number_of_arguments() { + comb(vec![EnvValue::Exp(Expression::CInt(5))]); } #[test] - fn test_lcm_common_multiples() { - assert_eq!(lcm(&50, &25), 50); - assert_eq!(lcm(&81, &27), 81); + #[should_panic(expected = "comb expects exactly two arguments")] + fn test_comb_invalid_number_of_arguments_multiple() { + comb(vec![ + EnvValue::Exp(Expression::CInt(5)), + EnvValue::Exp(Expression::CInt(2)), + EnvValue::Exp(Expression::CInt(1)), + ]); } #[test] - fn test_comb_basic_cases() { - assert_eq!(comb(&5, &3), 10); - assert_eq!(comb(&5, &0), 1); - assert_eq!(comb(&0, &0), 1); + #[should_panic(expected = "comb expects two integer arguments")] + fn test_comb_invalid_argument_type() { + comb(vec![EnvValue::Exp(Expression::CReal(5.0)), EnvValue::Exp(Expression::CInt(2))]); } #[test] - fn test_comb_large_values() { - assert_eq!(comb(&20, &10), 184_756); - assert_eq!(comb(&30, &15), 155_117_520); + #[should_panic(expected = "comb expects non-negative integers")] + fn test_comb_negative_arguments() { + comb(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(-2))]); } +//==================================================================================================== #[test] - fn test_comb_general_cases() { - assert_eq!(comb(&6, &2), 15); - assert_eq!(comb(&10, &5), 252); - assert_eq!(comb(&4, &4), 1); + fn test_perm_valid_inputs() { + let result = perm(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(2))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 20), + _ => panic!("Incorrect result for perm(5, 2)"), + } + + let result = perm(vec![EnvValue::Exp(Expression::CInt(10)), EnvValue::Exp(Expression::CInt(3))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 720), + _ => panic!("Incorrect result for perm(10, 3)"), + } + + let result = perm(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(6))]); + match result { + EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 0), + _ => panic!("Incorrect result for perm(5, 6)"), + } } #[test] - fn test_perm_basic_cases() { - assert_eq!(perm(&5, &3), 60); - assert_eq!(perm(&5, &0), 1); + #[should_panic(expected = "perm expects exactly two arguments")] + fn test_perm_invalid_number_of_arguments() { + perm(vec![EnvValue::Exp(Expression::CInt(5))]); } #[test] - fn test_perm_large_values() { - assert_eq!(perm(&20, &5), 1_860_480); - assert_eq!(perm(&10, &10), 3_628_800); + #[should_panic(expected = "perm expects exactly two arguments")] + fn test_perm_invalid_number_of_arguments_multiple() { + perm(vec![ + EnvValue::Exp(Expression::CInt(5)), + EnvValue::Exp(Expression::CInt(2)), + EnvValue::Exp(Expression::CInt(1)), + ]); } #[test] - fn test_perm_general_cases() { - assert_eq!(perm(&6, &2), 30); - assert_eq!(perm(&10, &3), 720); - assert_eq!(perm(&4, &4), 24); + #[should_panic(expected = "perm expects two integer arguments")] + fn test_perm_invalid_argument_type() { + perm(vec![EnvValue::Exp(Expression::CReal(5.0)), EnvValue::Exp(Expression::CInt(2))]); } -} \ No newline at end of file + #[test] + #[should_panic(expected = "perm expects non-negative integers")] + fn test_perm_negative_arguments() { + perm(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(-2))]); + } +} \ No newline at end of file diff --git a/src/tc/type_checker.rs b/src/tc/type_checker.rs index a3c7d26..664a62a 100644 --- a/src/tc/type_checker.rs +++ b/src/tc/type_checker.rs @@ -817,7 +817,7 @@ mod tests { ); let assign_stmt = Statement::Assignment( - "resultado".to_string(), + "result".to_string(), Box::new(Expression::Var("metaResult".to_string())), Some(Type::TReal), ); @@ -831,13 +831,13 @@ mod tests { Ok(ControlType::Continue(new_env)) => { let meta_result_type = new_env .get("metaResult") - .expect("metaResult não foi definido no ambiente") + .expect("metaResult was not found in the environment") .1 .clone(); assert_eq!(meta_result_type, Type::TReal); } - Ok(_) => panic!("O type checker não retornou um fluxo de controle esperado"), - Err(err) => panic!("Type checker falhou com erro: {}", err), + Ok(_) => panic!("Type checker should have returned a new environment"), + Err(err) => panic!("Type checker should not have failed: {}", err), } } @@ -859,7 +859,7 @@ mod tests { ); let assign_stmt = Statement::Assignment( - "resultado".to_string(), + "result".to_string(), Box::new(Expression::Var("metaResult".to_string())), Some(Type::TBool), ); @@ -871,7 +871,7 @@ mod tests { match check_stmt(program, &env, None) { Err(_err) => (), - Ok(_) => panic!("Type checker deveria ter falhado devido à incompatibilidade de tipos"), + Ok(_) => panic!("Type checker should have failed"), } } From c0b8c49d350eaf8ddcbcb64899ecadfa8525daae Mon Sep 17 00:00:00 2001 From: Layr Date: Sat, 15 Feb 2025 15:44:32 -0300 Subject: [PATCH 06/15] =?UTF-8?q?Adi=C3=A7=C3=A3o=20de=20MetaExpr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/interpreter/interpreter.rs | 171 ++++++++++++++++++++++++++++++++- src/ir/ast.rs | 1 + src/tc/type_checker.rs | 25 ++++- 3 files changed, 192 insertions(+), 5 deletions(-) diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 14a69a9..da9cfa1 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -1,4 +1,4 @@ -use crate::ir::ast::{EnvValue, Environment, Expression, Name, Statement}; +use crate::ir::ast::{EnvValue, Environment, Expression, Name, Statement, Type}; use crate::tc::type_checker::{check_stmt, ControlType}; use crate::HashMap; @@ -26,6 +26,7 @@ pub fn eval(exp: Expression, env: &Environment) -> Result lte(*lhs, *rhs, env), Expression::Var(name) => lookup(name, env), Expression::FuncCall(name, args) => call(name, args, env), + Expression::MetaExp(f, args, return_type) => meta(f, args, return_type, env), _ if is_constant(exp.clone()) => Ok(EnvValue::Exp(exp)), _ => Err(String::from("Not implemented yet.")), } @@ -445,6 +446,42 @@ fn lte(lhs: Expression, rhs: Expression, env: &Environment) -> Result) -> EnvValue, + args: Vec, + return_type: Type, + env: &Environment, +) -> Result { + + let mut args_values = Vec::new(); + for expr in &args { + let env_value = eval(expr.clone(), env)?; + args_values.push(env_value); + } + + let result_value = f(args_values); + + if get_type_env_value(&result_value) != return_type { + return Err(format!( + "Tipo incorreto: esperado {:?}, mas a função retornou {:?}", + return_type.clone(), + get_type_env_value(&result_value) + )); + } + Ok(result_value) +} + +pub fn get_type_env_value(value: &EnvValue) -> Type { + match value { + EnvValue::Exp(Expression::CInt(_)) => Type::TInteger, + EnvValue::Exp(Expression::CReal(_)) => Type::TReal, + EnvValue::Exp(Expression::CString(_)) => Type::TString, + EnvValue::Exp(Expression::CTrue) | EnvValue::Exp(Expression::CFalse) => Type::TBool, + EnvValue::Func(_) => Type::TFunction, + _ => unreachable!(), + } +} + #[cfg(test)] mod tests { use std::collections::HashMap; @@ -1021,7 +1058,7 @@ mod tests { * Imaginary rpy code: * * > x: TReal = 16.0 - * > MetaStmt(sqrt, [x]) + * > MetaStmt(sqrt, [x], TReal) * > result: TReal = metaResult * * After execution, 'result' should be 4.0 (sqrt(16.0) = 4.0). @@ -1077,7 +1114,7 @@ mod tests { * * > x: TReal = 25.0 * > def sqrt(x: TReal) -> TReal: - * > MetaStmt(sqrt, [x]) + * > MetaStmt(sqrt, [x], TReal) * > return metaResult * > x = sqrt(x) * @@ -1148,7 +1185,7 @@ mod tests { * > a: TInteger = 48 * > b: TInteger = 18 * > def gcd(a: TInteger, b: TInteger) -> TInteger: - * > MetaStmt(gcd, [a, b]) + * > MetaStmt(gcd, [a, b], TInteger) * > return metaResult * > result = gcd(a, b) * @@ -1219,4 +1256,130 @@ mod tests { } } + #[test] + fn metaexp_sqrt() { + /* + * Test for the r-python square root function (sqrt) using MetaExp + * + * Imaginary rpy code: + * + * > x: TReal = 25.0 + * > x = MetaExp(sqrt, [x], TReal) + * + * After execution, 'x' should be 5.0 (sqrt(25.0) = 5.0). + */ + + let env = Environment::new(); + + let assign_x = Statement::Assignment( + "x".to_string(), + Box::new(Expression::CReal(25.0)), + Some(Type::TReal), + ); + + let meta_expr = Expression::MetaExp( + sqrt, + vec![Expression::Var("x".to_string())], + Type::TReal, + ); + + let assign_result = Statement::Assignment( + "x".to_string(), + Box::new(meta_expr), + Some(Type::TReal), + ); + + let program = Statement::Sequence( + Box::new(assign_x), + Box::new(assign_result), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some(&(Some(EnvValue::Exp(Expression::CReal(value))), _)) = new_env.get("x") { + assert_eq!(value, 5.0); + } else { + panic!("Variable 'x' not found or has incorrect type"); + } + } + Ok(_) => panic!("The interpreter did not continue execution as expected"), + Err(err) => panic!("Interpreter execution failed with error: {}", err), + } + } + + #[test] + fn metaexp_function_gcd() { + /* + * Test for the greatest common divisor function (gcd) using MetaStmt + * + * Imaginary rpy code: + * + * > a: TInteger = 48 + * > b: TInteger = 18 + * > def gcd(a: TInteger, b: TInteger) -> TInteger: + * > return MetaStmt(gcd, [a, b], TInteger) + * > result = gcd(a, b) + * + * After execution, 'result' should be 6 (gcd(48, 18) = 6). + */ + + let env = Environment::new(); + + let assign_a = Statement::Assignment( + "a".to_string(), + Box::new(Expression::CInt(48)), + Some(TInteger), + ); + + let assign_b = Statement::Assignment( + "b".to_string(), + Box::new(Expression::CInt(18)), + Some(TInteger), + ); + + let meta_epx = Expression::MetaExp( + gcd, + vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], + TInteger, + ); + + let func = Statement::FuncDef( + "gcd".to_string(), + Function { + kind: TInteger, + params: Some(vec![("a".to_string(), TInteger), ("b".to_string(), TInteger)]), + body: Box::new(Statement::Return(Box::new(meta_epx))), + }, + ); + + let assign_result = Statement::Assignment( + "result".to_string(), + Box::new(Expression::FuncCall("gcd".to_string(), vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())])), + Some(TInteger), + ); + + let program = Statement::Sequence( + Box::new(assign_a), + Box::new(Statement::Sequence( + Box::new(assign_b), + Box::new(Statement::Sequence( + Box::new(func), + Box::new(assign_result), + )), + )), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some(&(Some(EnvValue::Exp(Expression::CInt(value))), _)) = new_env.get("result") { + assert_eq!(value, 6); + } else { + panic!("Variable 'result' not found or has incorrect type"); + } + } + Ok(_) => panic!("The interpreter did not continue execution as expected"), + Err(err) => panic!("Interpreter execution failed with error: {}", err), + } + } + } diff --git a/src/ir/ast.rs b/src/ir/ast.rs index d39b910..766bb6d 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -43,6 +43,7 @@ pub enum Expression { /* function call */ FuncCall(Name, Vec), + MetaExp(fn(Vec) -> EnvValue, Vec, Type), /* arithmetic expressions over numbers */ Add(Box, Box), diff --git a/src/tc/type_checker.rs b/src/tc/type_checker.rs index 664a62a..ce0f01f 100644 --- a/src/tc/type_checker.rs +++ b/src/tc/type_checker.rs @@ -28,6 +28,12 @@ pub fn check_exp(exp: Expression, env: &Environment) -> Result check_bin_relational_expression(*l, *r, env), Expression::Var(name) => check_var_name(name, env), Expression::FuncCall(name, args) => check_func_call(name, args, env), + Expression::MetaExp(_, args, return_type) => { + for arg in args { + check_exp(arg.clone(), env)?; + } + Ok(return_type) + } } } @@ -155,7 +161,7 @@ pub fn check_stmt( Ok(ControlType::Return(exp_type)) } - Statement::MetaStmt(_f, args, return_type) => { + Statement::MetaStmt(_, args, return_type) => { for arg in args { check_exp(arg.clone(), env)?; } @@ -875,4 +881,21 @@ mod tests { } } + #[test] + fn check_metaexp_sqrt_correct() { + let mut env = Environment::new(); + env.insert( + "x".to_string(), + (Some(EnvValue::Exp(Expression::CReal(25.0))), Type::TReal), + ); + + let meta_expr = Expression::MetaExp( + sqrt, + vec![Expression::Var("x".to_string())], + Type::TReal, + ); + + let ty = check_exp(meta_expr, &env).unwrap(); + assert_eq!(ty, Type::TReal); + } } From 9ec5bb06b445e0815e7dfe04d34958d894b684b8 Mon Sep 17 00:00:00 2001 From: Marquito-2003 Date: Sat, 15 Feb 2025 19:52:16 -0300 Subject: [PATCH 07/15] =?UTF-8?q?Altera=C3=A7=C3=B5es=20em=20math.rs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.rs | 2 + src/stdlib/math.rs | 779 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 781 insertions(+) diff --git a/src/main.rs b/src/main.rs index fe37829..5c78518 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,8 @@ pub mod parser; pub mod tc; pub mod stdlib; + + fn run_test(name: &str, program: &str) -> String { let mut output = String::new(); output.push_str(&format!("\n=== Running test: {} ===\n", name)); diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs index 58e92d3..ef5d037 100644 --- a/src/stdlib/math.rs +++ b/src/stdlib/math.rs @@ -1,4 +1,6 @@ use crate::ir::ast::{EnvValue, Expression}; +use crate::ir::ast::Environment; +use std::collections::HashMap; pub fn sqrt(args: Vec) -> EnvValue { if args.len() != 1 { @@ -12,6 +14,467 @@ pub fn sqrt(args: Vec) -> EnvValue { } } +pub fn len(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("len espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { + let mut contador = 0; + for _ in lista { + contador += 1; + } + return EnvValue::Exp(Expression::CInt(contador as i32)); + } else { + panic!("len espera um argumento do tipo lista"); + } +} + +pub fn max(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("max espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { + + + // Inicializar o valor máximo com o primeiro elemento da lista + let mut achei_max = match lista[0] { + Expression::CInt(val) => val, + _ => panic!("max espera uma lista de inteiros"), + }; + + // Iterar sobre a lista e encontrar o valor máximo + for expr in &lista[1..] { + if let Expression::CInt(val) = expr { + if *val > achei_max { + achei_max = *val; // Atualiza achei_max com o valor do inteiro + } + } else { + panic!("max espera uma lista de inteiros"); + } + } + + return EnvValue::Exp(Expression::CInt(achei_max)); + } else { + panic!("max espera um argumento do tipo lista"); + } +} + +pub fn min(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("max espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { + + + // Inicializar o valor máximo com o primeiro elemento da lista + let mut achei_min = match lista[0] { + Expression::CInt(val) => val, + _ => panic!("min espera uma lista de inteiros"), + }; + + // Iterar sobre a lista e encontrar o valor máximo + for expr in &lista[1..] { + if let Expression::CInt(val) = expr { + if *val == achei_min { + achei_min = *val; // Atualiza achei_max com o valor do inteiro + } + } else { + panic!("min espera uma lista de inteiros"); + } + } + + return EnvValue::Exp(Expression::CInt(achei_min)); + } else { + panic!("min espera um argumento do tipo lista"); + } +} + +pub fn index(args: Vec, target: i32) -> EnvValue { + if args.len() != 1 { + panic!("index espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { + let mut contador = 0; + + // Iterar sobre a lista e encontrar o índice + for expr in lista { + if let Expression::CInt(val) = expr { + if *val == target { + return EnvValue::Exp(Expression::CInt(contador)); + } + contador +=1; + } else { + panic!("index espera uma lista de inteiros"); + } + } + return EnvValue::Exp(Expression::CInt(-1)); + + } else { + panic!("index espera um argumento do tipo lista"); + } +} + +pub fn remove(args: Vec, target: i32) -> EnvValue { + if args.len() != 1 { + panic!("remove espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { + let mut lista_nova = vec![]; + + // Iterar sobre a lista e remover o valor alvo (target) + for expr in lista { + if let Expression::CInt(val) = expr { + if *val != target { + lista_nova.push(Expression::CInt(*val)); + } + } else { + panic!("remove espera uma lista de inteiros"); + } + } + + return EnvValue::Exp(Expression::FuncCall(name.clone(), lista_nova)); + } else { + panic!("remove espera um argumento do tipo lista"); + } +} + +pub fn zip(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("zip espera exatamente dois argumentos"); + } + + if let (EnvValue::Exp(Expression::FuncCall(name1, lista1)), EnvValue::Exp(Expression::FuncCall(name2, lista2))) = (&args[0], &args[1]) { + let zipped_list: Vec = lista1.iter().zip(lista2.iter()) + .map(|(a, b)| Expression::FuncCall("pair".to_string(), vec![a.clone(), b.clone()])) + .collect(); + return EnvValue::Exp(Expression::FuncCall("zipped_list".to_string(), zipped_list)); + } else { + panic!("zip espera argumentos do tipo lista"); + } +} + +pub fn enumerate(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("enumerate espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { + let mut tupla = vec![]; + + // Iterar sobre a lista e criar tuplas (index, item) + for (index, item) in lista.iter().enumerate() { + if let Expression::CInt(val) = item { + tupla.push(Expression::FuncCall("pair".to_string(), vec![ + Expression::CInt(index as i32), + Expression::CInt(*val), + ])); + } else { + panic!("enumerate espera uma lista de inteiros"); + } + } + return EnvValue::Exp(Expression::FuncCall("tupla_list".to_string(), tupla)); + } else { + panic!("enumerate espera um argumento do tipo lista"); + } +} + +pub fn sort(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("sort espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { + let mut result: Vec = lista.clone(); + let len = result.len(); + + for i in 0..len { + for j in 0..len - i - 1 { + if let (Expression::CInt(val1), Expression::CInt(val2)) = (&result[j], &result[j + 1]) { + if val1 > val2 { + let temp = result[j].clone(); + result[j] = result[j + 1].clone(); + result[j + 1] = temp; + } + } else { + panic!("sort espera uma lista de inteiros"); + } + } + } + + return EnvValue::Exp(Expression::FuncCall(name.clone(), result)); + } else { + panic!("sort espera um argumento do tipo lista"); + } +} + +pub fn str_upper(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("str_upper expects exactly one argument"); + } + + if let EnvValue::Exp(Expression::CString(s)) = &args[0] { + EnvValue::Exp(Expression::CString(s.to_uppercase())) + } else { + panic!("str_upper expects a string argument"); + } +} + +pub fn str_lower(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("str_lower expects exactly one argument"); + } + if let EnvValue::Exp(Expression::CString(s)) = &args[0] { + EnvValue::Exp(Expression::CString(s.to_lowercase())) + } else { + panic!("str_lower expects a string argument"); + } +} + +pub fn str_length(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("str_length expects exactly one argument"); + } + if let EnvValue::Exp(Expression::CString(s)) = &args[0] { + EnvValue::Exp(Expression::CInt(s.chars().count() as i32)) + } else { + panic!("str_length expects a string argument"); + } +} + +pub fn str_reverse(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("str_reverse expects exactly one argument"); + } + if let EnvValue::Exp(Expression::CString(s)) = &args[0] { + EnvValue::Exp(Expression::CString(s.chars().rev().collect())) + } else { + panic!("str_reverse expects a string argument"); + } +} + +//conta quantas vezes aparece um char especifico +pub fn cont_chars(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("cont_chars expects exactly two arguments"); + } + if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = (&args[0], &args[1]) { + if c.len() != 1 { + panic!("cont_chars expects a single character as the second argument"); + } + let target = c.chars().next().unwrap(); + EnvValue::Exp(Expression::CInt(s.chars().filter(|&ch| ch == target).count() as i32)) + } else { + panic!("cont_chars expects a string and a character as arguments"); + } +} + +//retira todas as aparicoes de um char especifico +pub fn filter_out_char(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("filter_out_char expects exactly two arguments"); + } + if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = (&args[0], &args[1]) { + if c.len() != 1 { + panic!("filter_out_char expects a single character as the second argument"); + } + let target = c.chars().next().unwrap(); + EnvValue::Exp(Expression::CString(s.chars().filter(|&ch| ch != target).collect())) + } else { + panic!("filter_out_char expects a string and a character as arguments"); + } +} + +// substitui os N primeiros caracteres "old" por um novo caracter "new" +pub fn replace(args: Vec) -> EnvValue { + if args.len() < 3 || args.len() > 4 { + panic!("replace expects between 3 and 4 arguments"); + } + if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(old)), EnvValue::Exp(Expression::CString(new))) = (&args[0], &args[1], &args[2]) { + let count = if args.len() == 4 { + if let EnvValue::Exp(Expression::CInt(n)) = &args[3] { + *n + } else { + panic!("replace expects an integer as the fourth argument (count)"); + } + } else { + -1 + }; + + let result = if count < 0 { + s.replace(old, new) + } else { + let mut result = s.clone(); + let mut occurrences = 0; + while occurrences < count { + if let Some(pos) = result.find(old) { + result = format!("{}{}{}", &result[..pos], new, &result[pos + old.len()..]); + occurrences += 1; + } else { + break; + } + } + result + }; + + EnvValue::Exp(Expression::CString(result)) + } else { + panic!("replace expects three string arguments and an optional integer"); + } +} + +//centraliza a string e preenche o resto com um char +pub fn center(args: Vec) -> EnvValue { + if args.len() != 3 { + panic!("center expects exactly three arguments"); + } + + if let ( + EnvValue::Exp(Expression::CString(s)), + EnvValue::Exp(Expression::CInt(width)), + EnvValue::Exp(Expression::CString(fillchar)), + ) = (&args[0], &args[1], &args[2]) + { + if fillchar.len() != 1 { + panic!("center expects a single character as the fill character"); + } + + let fill = fillchar.chars().next().unwrap(); + let pad = (*width as usize).saturating_sub(s.len()); + let left = pad / 2; + let right = pad - left; + + let centered = format!( + "{}{}{}", + fill.to_string().repeat(left), + s, + fill.to_string().repeat(right) + ); + + EnvValue::Exp(Expression::FuncCall( + "center".to_string(), + vec![Expression::CString(centered)], + )) + } else { + panic!("center expects a string, an integer width, and a character as arguments"); + } +} + +//acha uma substring +pub fn find(args: Vec) -> EnvValue { + if args.len() < 2 || args.len() > 4 { + panic!("find expects between 2 and 4 arguments"); + } + + if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(sub))) = + (&args[0], &args[1]) + { + let start = if args.len() > 2 { + if let EnvValue::Exp(Expression::CInt(n)) = &args[2] { + *n as usize + } else { + panic!("find expects an integer as the third argument (start index)"); + } + } else { + 0 + }; + + let end = if args.len() > 3 { + if let EnvValue::Exp(Expression::CInt(n)) = &args[3] { + Some(*n as usize) + } else { + panic!("find expects an integer as the fourth argument (end index)"); + } + } else { + None + }; + + let end = end.unwrap_or(s.len()); + let result = match s.get(start..end) { + Some(substring) => substring.find(sub).map(|i| i + start), + None => None, + }; + + let retorno = match result { + Some(index) => EnvValue::Exp(Expression::CInt(index as i32)), + None => EnvValue::Exp(Expression::CInt(-1)), + }; + + if let EnvValue::Exp(expr) = retorno { + EnvValue::Exp(Expression::FuncCall("find".to_string(), vec![expr])) + } else { + panic!("invalid return value type"); + } + + } else { + panic!("find expects two strings as first arguments"); + } +} + +//recebe uma lista de strings e junta elas em uma string so +pub fn join(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("join expects exactly two arguments"); + } + + if let ( + EnvValue::Exp(Expression::CString(sep)), + EnvValue::Exp(Expression::FuncCall(_, lista)), + ) = (&args[0], &args[1]) + { + let strings: Vec = lista + .iter() + .map(|expr| { + if let Expression::CString(s) = expr { + s.clone() + } else { + panic!("join expects a list of strings as the second argument"); + } + }) + .collect(); + + EnvValue::Exp(Expression::CString(strings.join(sep))) + } else { + panic!("join expects a string and a list of strings as arguments"); + } +} + +pub fn partition(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("partition expects exactly two arguments"); + } + + if let ( + EnvValue::Exp(Expression::CString(s)), + EnvValue::Exp(Expression::CString(sep)), + ) = (&args[0], &args[1]) + { + match s.find(sep) { + Some(index) => EnvValue::Exp(Expression::FuncCall( + "tuple".to_string(), + vec![ + Expression::CString(s[..index].to_string()), + Expression::CString(sep.clone()), + Expression::CString(s[index + sep.len()..].to_string()), + ], + )), + None => EnvValue::Exp(Expression::FuncCall( + "tuple".to_string(), + vec![ + Expression::CString(s.to_string()), + Expression::CString(String::new()), + Expression::CString(String::new()), + ], + )), + } + } else { + panic!("partition expects two string arguments"); + } +} pub fn factorial(args: Vec) -> EnvValue { if args.len() != 1 { @@ -142,6 +605,322 @@ mod tests { } } + #[test] + fn test_len() { + let lista = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(3), + ]; + + let result = len(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); + + match result { + EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 3), + _ => panic!("Resultado incorreto para len([1, 2, 3])"), + } + } + + #[test] + fn test_max() { + let lista = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(5), + ]; + + let result = max(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); + + match result { + EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 5), + _ => panic!("Resultado incorreto para len([1, 2, 5])"), + } + } + + #[test] + fn test_min() { + let lista = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(5), + ]; + + let result = min(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); + + match result { + EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 1), + _ => panic!("Resultado incorreto para len([1, 2, 5])"), + } + } + + #[test] + fn test_index() { + let lista = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(5), + ]; + + let result = index(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))], 5); + + match result { + EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 2), // O índice do valor 5 é 2 + _ => panic!("Resultado incorreto para index([1, 2, 5], 5)"), + } + } + + + #[test] + fn test_remove() { + let lista = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(5), + ]; + + let result = remove(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))], 2); + + match result { + EnvValue::Exp(Expression::FuncCall(_, nova_lista)) => { + let expected = vec![ + Expression::CInt(1), + Expression::CInt(5), + ]; + assert_eq!(nova_lista, expected); + }, + _ => panic!("Resultado incorreto para remove([1, 2, 5], 2)"), + } + } + + #[test] + fn test_zip() { + let lista1 = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(3), + ]; + let lista2 = vec![ + Expression::CInt(4), + Expression::CInt(5), + Expression::CInt(6), + ]; + + let result = zip(vec![ + EnvValue::Exp(Expression::FuncCall("lista1".to_string(), lista1)), + EnvValue::Exp(Expression::FuncCall("lista2".to_string(), lista2)) + ]); + + match result { + EnvValue::Exp(Expression::FuncCall(_, zipped_list)) => { + let expected = vec![ + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(1), Expression::CInt(4)]), + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(2), Expression::CInt(5)]), + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(3), Expression::CInt(6)]), + ]; + assert_eq!(zipped_list, expected); + }, + _ => panic!("Resultado incorreto para zip([1, 2, 3], [4, 5, 6])"), + } + } + + #[test] + fn test_enumerate() { + let lista = vec![ + Expression::CInt(10), + Expression::CInt(20), + Expression::CInt(30), + ]; + + let result = enumerate(vec![EnvValue::Exp(Expression::FuncCall("lista".to_string(), lista))]); + + match result { + EnvValue::Exp(Expression::FuncCall(_, tupla_list)) => { + let expected = vec![ + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(0), Expression::CInt(10)]), + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(1), Expression::CInt(20)]), + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(2), Expression::CInt(30)]), + ]; + assert_eq!(tupla_list, expected); + }, + _ => panic!("Resultado incorreto para enumerate([10, 20, 30])"), + } + } + + #[test] + fn test_sort() { + let lista = vec![ + Expression::CInt(3), + Expression::CInt(1), + Expression::CInt(4), + Expression::CInt(1), + Expression::CInt(5), + Expression::CInt(9), + Expression::CInt(2), + Expression::CInt(6), + Expression::CInt(5), + ]; + + let result = sort(vec![EnvValue::Exp(Expression::FuncCall("lista".to_string(), lista))]); + + match result { + EnvValue::Exp(Expression::FuncCall(_, sorted_list)) => { + let expected = vec![ + Expression::CInt(1), + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(3), + Expression::CInt(4), + Expression::CInt(5), + Expression::CInt(5), + Expression::CInt(6), + Expression::CInt(9), + ]; + assert_eq!(sorted_list, expected); + }, + _ => panic!("Resultado incorreto para sort([3, 1, 4, 1, 5, 9, 2, 6, 5])"), + } + } + + #[test] + fn test_str_lower_valid_strings() { + let result = str_lower(vec![EnvValue::Exp(Expression::CString(String::from("HELLO")))]); + match result { + EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "hello"), + _ => panic!("Incorrect result for str_lower('HELLO')"), + } + } + + #[test] + fn test_str_length_valid_string() { + let result = str_length(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); + match result { + EnvValue::Exp(Expression::CInt(len)) => assert_eq!(len, 5), + _ => panic!("Incorrect result for str_length('hello')"), + } + } + + #[test] + fn test_str_reverse_valid_string() { + let result = str_reverse(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); + match result { + EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "olleh"), + _ => panic!("Incorrect result for str_reverse('hello')"), + } + } + + #[test] + fn test_cont_chars_valid_input() { + let result = cont_chars(vec![ + EnvValue::Exp(Expression::CString(String::from("banana"))), + EnvValue::Exp(Expression::CString(String::from("a"))), + ]); + match result { + EnvValue::Exp(Expression::CInt(count)) => assert_eq!(count, 3), + _ => panic!("Incorrect result for cont_chars('banana', 'a')"), + } + } + + #[test] + fn test_filter_out_char_valid_input() { + let result = filter_out_char(vec![ + EnvValue::Exp(Expression::CString(String::from("banana"))), + EnvValue::Exp(Expression::CString(String::from("a"))), + ]); + match result { + EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "bnn"), + _ => panic!("Incorrect result for filter_out_char('banana', 'a')"), + } + } + + #[test] + fn test_replace_valid_input() { + let result = replace(vec![ + EnvValue::Exp(Expression::CString(String::from("banana"))), + EnvValue::Exp(Expression::CString(String::from("a"))), + EnvValue::Exp(Expression::CString(String::from("o"))), + ]); + match result { + EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "bonono"), + _ => panic!("Incorrect result for replace('banana', 'a', 'o')"), + } + } + + #[test] + fn test_center_valid_input() { + let result = center(vec![ + EnvValue::Exp(Expression::CString(String::from("hello"))), + EnvValue::Exp(Expression::CInt(11)), + EnvValue::Exp(Expression::CString(String::from("*"))), + ]); + match result { + EnvValue::Exp(Expression::FuncCall(_, args)) => { + if let Expression::CString(centered) = &args[0] { + assert_eq!(centered, "***hello***"); + } else { + panic!("Incorrect result for center('hello', 11, '*')"); + } + } + _ => panic!("Incorrect return type for center"), + } + } + + #[test] + fn test_find_valid_input() { + let result = find(vec![ + EnvValue::Exp(Expression::CString(String::from("hello world"))), + EnvValue::Exp(Expression::CString(String::from("world"))), + ]); + match result { + EnvValue::Exp(Expression::FuncCall(_, args)) => { + if let Expression::CInt(index) = &args[0] { + assert_eq!(*index, 6); + } else { + panic!("Incorrect result for find('hello world', 'world')"); + } + } + _ => panic!("Incorrect return type for find"), + } + } + + #[test] + fn test_join_valid_input() { + let result = join(vec![ + EnvValue::Exp(Expression::CString(String::from(","))), + EnvValue::Exp(Expression::FuncCall( + "list".to_string(), + vec![ + Expression::CString(String::from("a")), + Expression::CString(String::from("b")), + Expression::CString(String::from("c")), + ], + )), + ]); + match result { + EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "a,b,c"), + _ => panic!("Incorrect result for join(',', ['a', 'b', 'c'])"), + } + } + + #[test] + fn test_partition_valid_input() { + let result = partition(vec![ + EnvValue::Exp(Expression::CString(String::from("banana"))), + EnvValue::Exp(Expression::CString(String::from("n"))), + ]); + match result { + EnvValue::Exp(Expression::FuncCall(_, args)) => { + if let (Expression::CString(left), Expression::CString(sep), Expression::CString(right)) = (&args[0], &args[1], &args[2]) { + assert_eq!(left, "ba"); + assert_eq!(sep, "n"); + assert_eq!(right, "ana"); + } else { + panic!("Incorrect result for partition('banana', 'n')"); + } + } + _ => panic!("Incorrect return type for partition"), + } + } + #[test] fn test_sqrt_zero() { let result = sqrt(vec![EnvValue::Exp(Expression::CReal(0.0))]); From 610e13c2c310a0a49bcbb7a54365ecd5a3df689a Mon Sep 17 00:00:00 2001 From: Marquito-2003 Date: Sat, 15 Feb 2025 22:55:53 -0300 Subject: [PATCH 08/15] =?UTF-8?q?Separa=C3=A7=C3=A3o=20das=20fun=C3=A7?= =?UTF-8?q?=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/interpreter/interpreter.rs | 69 +++ src/stdlib.rs | 4 +- src/stdlib/list.rs | 382 ++++++++++++++++ src/stdlib/math.rs | 775 --------------------------------- src/stdlib/string.rs | 410 +++++++++++++++++ 5 files changed, 864 insertions(+), 776 deletions(-) create mode 100644 src/stdlib/list.rs create mode 100644 src/stdlib/string.rs diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index da9cfa1..8185272 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -492,6 +492,9 @@ mod tests { use crate::ir::ast::Statement::*; use crate::ir::ast::Type::*; use crate::stdlib::math::{sqrt, gcd}; + use crate::stdlib::string::{str_upper}; + use crate::stdlib::list::{len}; + use approx::relative_eq; #[test] @@ -1382,4 +1385,70 @@ mod tests { } } + #[test] + fn metastmt_function_upper(){ + /* + * Test for the r-python square root function (sqrt) using MetaStmt + * + * Imaginary rpy code: + * + * > x: TString = "banana" + * > def upper(x: TString) -> TString: + * > MetaStmt(str_upper, [x], TString) + * > return metaResult + * > x = upper(x) + * + * After execution, 'x' should be 5.0 (sqrt(25.0) = 5.0). + */ + let env = Environment::new(); + let assign_x = Statement::Assignment( + "x".to_string(), + Box::new(Expression::CString("banana".to_string())), + Some(TString) + ); + let meta_stmt = Statement::MetaStmt( + str_upper, + vec![Expression::Var("x".to_string())], + TString + ); + let func = Statement::FuncDef( + "upper".to_string(), + Function{ + kind: TString, + params: Some(vec![("x".to_string(), TString)]), + body: Box::new(Sequence( + Box::new(meta_stmt), + Box::new(Return( + Box::new(Expression::Var("metaResult".to_string())) + )) + )) + } + ); + let assign_result = Statement::Assignment( + "x".to_string(), + Box::new(Expression::FuncCall("upper".to_string(), vec![Expression::Var("x".to_string())])), + Some(TString), + ); + let program = Statement::Sequence( + Box::new(assign_x), + Box::new(Statement::Sequence( + Box::new(func), + Box::new(assign_result) + )) + ); + match execute(program, &env, true){ + Ok(ControlFlow::Continue(new_env)) => { + if let Some(&(Some(EnvValue::Exp(Expression::CString(ref value))), _)) = new_env.get("x"){ + assert_eq!(value, &"BANANA".to_string()); + } else{ + panic!("Variable 'x' not found or has incorret type"); + } + + } + Ok(_) => panic!("The interpreter did not continue execution as expect"), + Err(err) => panic!("Interpreter execution failed with error: {}", err), + + } + } + } diff --git a/src/stdlib.rs b/src/stdlib.rs index 354c7c9..1d02495 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -1 +1,3 @@ -pub mod math; \ No newline at end of file +pub mod math; +pub mod list; +pub mod string; \ No newline at end of file diff --git a/src/stdlib/list.rs b/src/stdlib/list.rs new file mode 100644 index 0000000..09103b8 --- /dev/null +++ b/src/stdlib/list.rs @@ -0,0 +1,382 @@ +use crate::ir::ast::{EnvValue, Expression}; +use crate::ir::ast::Environment; +use std::collections::HashMap; + +pub fn len(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("len espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { + let mut contador = 0; + for _ in lista { + contador += 1; + } + return EnvValue::Exp(Expression::CInt(contador as i32)); + } else { + panic!("len espera um argumento do tipo lista"); + } +} + +pub fn max(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("max espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { + + + // Inicializar o valor máximo com o primeiro elemento da lista + let mut achei_max = match lista[0] { + Expression::CInt(val) => val, + _ => panic!("max espera uma lista de inteiros"), + }; + + // Iterar sobre a lista e encontrar o valor máximo + for expr in &lista[1..] { + if let Expression::CInt(val) = expr { + if *val > achei_max { + achei_max = *val; // Atualiza achei_max com o valor do inteiro + } + } else { + panic!("max espera uma lista de inteiros"); + } + } + + return EnvValue::Exp(Expression::CInt(achei_max)); + } else { + panic!("max espera um argumento do tipo lista"); + } +} + +pub fn min(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("max espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { + + + // Inicializar o valor máximo com o primeiro elemento da lista + let mut achei_min = match lista[0] { + Expression::CInt(val) => val, + _ => panic!("min espera uma lista de inteiros"), + }; + + // Iterar sobre a lista e encontrar o valor máximo + for expr in &lista[1..] { + if let Expression::CInt(val) = expr { + if *val == achei_min { + achei_min = *val; // Atualiza achei_max com o valor do inteiro + } + } else { + panic!("min espera uma lista de inteiros"); + } + } + + return EnvValue::Exp(Expression::CInt(achei_min)); + } else { + panic!("min espera um argumento do tipo lista"); + } +} + +pub fn index(args: Vec, target: i32) -> EnvValue { + if args.len() != 1 { + panic!("index espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { + let mut contador = 0; + + // Iterar sobre a lista e encontrar o índice + for expr in lista { + if let Expression::CInt(val) = expr { + if *val == target { + return EnvValue::Exp(Expression::CInt(contador)); + } + contador +=1; + } else { + panic!("index espera uma lista de inteiros"); + } + } + return EnvValue::Exp(Expression::CInt(-1)); + + } else { + panic!("index espera um argumento do tipo lista"); + } +} + +pub fn remove(args: Vec, target: i32) -> EnvValue { + if args.len() != 1 { + panic!("remove espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { + let mut lista_nova = vec![]; + + // Iterar sobre a lista e remover o valor alvo (target) + for expr in lista { + if let Expression::CInt(val) = expr { + if *val != target { + lista_nova.push(Expression::CInt(*val)); + } + } else { + panic!("remove espera uma lista de inteiros"); + } + } + + return EnvValue::Exp(Expression::FuncCall(name.clone(), lista_nova)); + } else { + panic!("remove espera um argumento do tipo lista"); + } +} + +pub fn zip(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("zip espera exatamente dois argumentos"); + } + + if let (EnvValue::Exp(Expression::FuncCall(name1, lista1)), EnvValue::Exp(Expression::FuncCall(name2, lista2))) = (&args[0], &args[1]) { + let zipped_list: Vec = lista1.iter().zip(lista2.iter()) + .map(|(a, b)| Expression::FuncCall("pair".to_string(), vec![a.clone(), b.clone()])) + .collect(); + return EnvValue::Exp(Expression::FuncCall("zipped_list".to_string(), zipped_list)); + } else { + panic!("zip espera argumentos do tipo lista"); + } +} + +pub fn enumerate(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("enumerate espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { + let mut tupla = vec![]; + + // Iterar sobre a lista e criar tuplas (index, item) + for (index, item) in lista.iter().enumerate() { + if let Expression::CInt(val) = item { + tupla.push(Expression::FuncCall("pair".to_string(), vec![ + Expression::CInt(index as i32), + Expression::CInt(*val), + ])); + } else { + panic!("enumerate espera uma lista de inteiros"); + } + } + return EnvValue::Exp(Expression::FuncCall("tupla_list".to_string(), tupla)); + } else { + panic!("enumerate espera um argumento do tipo lista"); + } +} + +pub fn sort(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("sort espera exatamente um argumento"); + } + + if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { + let mut result: Vec = lista.clone(); + let len = result.len(); + + for i in 0..len { + for j in 0..len - i - 1 { + if let (Expression::CInt(val1), Expression::CInt(val2)) = (&result[j], &result[j + 1]) { + if val1 > val2 { + let temp = result[j].clone(); + result[j] = result[j + 1].clone(); + result[j + 1] = temp; + } + } else { + panic!("sort espera uma lista de inteiros"); + } + } + } + + return EnvValue::Exp(Expression::FuncCall(name.clone(), result)); + } else { + panic!("sort espera um argumento do tipo lista"); + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_len() { + let lista = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(3), + ]; + + let result = len(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); + + match result { + EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 3), + _ => panic!("Resultado incorreto para len([1, 2, 3])"), + } + } + + #[test] + fn test_max() { + let lista = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(5), + ]; + + let result = max(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); + + match result { + EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 5), + _ => panic!("Resultado incorreto para len([1, 2, 5])"), + } + } + + #[test] + fn test_min() { + let lista = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(5), + ]; + + let result = min(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); + + match result { + EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 1), + _ => panic!("Resultado incorreto para len([1, 2, 5])"), + } + } + + #[test] + fn test_index() { + let lista = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(5), + ]; + + let result = index(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))], 5); + + match result { + EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 2), // O índice do valor 5 é 2 + _ => panic!("Resultado incorreto para index([1, 2, 5], 5)"), + } + } + + + #[test] + fn test_remove() { + let lista = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(5), + ]; + + let result = remove(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))], 2); + + match result { + EnvValue::Exp(Expression::FuncCall(_, nova_lista)) => { + let expected = vec![ + Expression::CInt(1), + Expression::CInt(5), + ]; + assert_eq!(nova_lista, expected); + }, + _ => panic!("Resultado incorreto para remove([1, 2, 5], 2)"), + } + } + + #[test] + fn test_zip() { + let lista1 = vec![ + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(3), + ]; + let lista2 = vec![ + Expression::CInt(4), + Expression::CInt(5), + Expression::CInt(6), + ]; + + let result = zip(vec![ + EnvValue::Exp(Expression::FuncCall("lista1".to_string(), lista1)), + EnvValue::Exp(Expression::FuncCall("lista2".to_string(), lista2)) + ]); + + match result { + EnvValue::Exp(Expression::FuncCall(_, zipped_list)) => { + let expected = vec![ + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(1), Expression::CInt(4)]), + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(2), Expression::CInt(5)]), + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(3), Expression::CInt(6)]), + ]; + assert_eq!(zipped_list, expected); + }, + _ => panic!("Resultado incorreto para zip([1, 2, 3], [4, 5, 6])"), + } + } + + #[test] + fn test_enumerate() { + let lista = vec![ + Expression::CInt(10), + Expression::CInt(20), + Expression::CInt(30), + ]; + + let result = enumerate(vec![EnvValue::Exp(Expression::FuncCall("lista".to_string(), lista))]); + + match result { + EnvValue::Exp(Expression::FuncCall(_, tupla_list)) => { + let expected = vec![ + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(0), Expression::CInt(10)]), + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(1), Expression::CInt(20)]), + Expression::FuncCall("pair".to_string(), vec![Expression::CInt(2), Expression::CInt(30)]), + ]; + assert_eq!(tupla_list, expected); + }, + _ => panic!("Resultado incorreto para enumerate([10, 20, 30])"), + } + } + + #[test] + fn test_sort() { + let lista = vec![ + Expression::CInt(3), + Expression::CInt(1), + Expression::CInt(4), + Expression::CInt(1), + Expression::CInt(5), + Expression::CInt(9), + Expression::CInt(2), + Expression::CInt(6), + Expression::CInt(5), + ]; + + let result = sort(vec![EnvValue::Exp(Expression::FuncCall("lista".to_string(), lista))]); + + match result { + EnvValue::Exp(Expression::FuncCall(_, sorted_list)) => { + let expected = vec![ + Expression::CInt(1), + Expression::CInt(1), + Expression::CInt(2), + Expression::CInt(3), + Expression::CInt(4), + Expression::CInt(5), + Expression::CInt(5), + Expression::CInt(6), + Expression::CInt(9), + ]; + assert_eq!(sorted_list, expected); + }, + _ => panic!("Resultado incorreto para sort([3, 1, 4, 1, 5, 9, 2, 6, 5])"), + } + } + +} \ No newline at end of file diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs index ef5d037..9d08e36 100644 --- a/src/stdlib/math.rs +++ b/src/stdlib/math.rs @@ -14,468 +14,6 @@ pub fn sqrt(args: Vec) -> EnvValue { } } -pub fn len(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("len espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { - let mut contador = 0; - for _ in lista { - contador += 1; - } - return EnvValue::Exp(Expression::CInt(contador as i32)); - } else { - panic!("len espera um argumento do tipo lista"); - } -} - -pub fn max(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("max espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { - - - // Inicializar o valor máximo com o primeiro elemento da lista - let mut achei_max = match lista[0] { - Expression::CInt(val) => val, - _ => panic!("max espera uma lista de inteiros"), - }; - - // Iterar sobre a lista e encontrar o valor máximo - for expr in &lista[1..] { - if let Expression::CInt(val) = expr { - if *val > achei_max { - achei_max = *val; // Atualiza achei_max com o valor do inteiro - } - } else { - panic!("max espera uma lista de inteiros"); - } - } - - return EnvValue::Exp(Expression::CInt(achei_max)); - } else { - panic!("max espera um argumento do tipo lista"); - } -} - -pub fn min(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("max espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { - - - // Inicializar o valor máximo com o primeiro elemento da lista - let mut achei_min = match lista[0] { - Expression::CInt(val) => val, - _ => panic!("min espera uma lista de inteiros"), - }; - - // Iterar sobre a lista e encontrar o valor máximo - for expr in &lista[1..] { - if let Expression::CInt(val) = expr { - if *val == achei_min { - achei_min = *val; // Atualiza achei_max com o valor do inteiro - } - } else { - panic!("min espera uma lista de inteiros"); - } - } - - return EnvValue::Exp(Expression::CInt(achei_min)); - } else { - panic!("min espera um argumento do tipo lista"); - } -} - -pub fn index(args: Vec, target: i32) -> EnvValue { - if args.len() != 1 { - panic!("index espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { - let mut contador = 0; - - // Iterar sobre a lista e encontrar o índice - for expr in lista { - if let Expression::CInt(val) = expr { - if *val == target { - return EnvValue::Exp(Expression::CInt(contador)); - } - contador +=1; - } else { - panic!("index espera uma lista de inteiros"); - } - } - return EnvValue::Exp(Expression::CInt(-1)); - - } else { - panic!("index espera um argumento do tipo lista"); - } -} - -pub fn remove(args: Vec, target: i32) -> EnvValue { - if args.len() != 1 { - panic!("remove espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { - let mut lista_nova = vec![]; - - // Iterar sobre a lista e remover o valor alvo (target) - for expr in lista { - if let Expression::CInt(val) = expr { - if *val != target { - lista_nova.push(Expression::CInt(*val)); - } - } else { - panic!("remove espera uma lista de inteiros"); - } - } - - return EnvValue::Exp(Expression::FuncCall(name.clone(), lista_nova)); - } else { - panic!("remove espera um argumento do tipo lista"); - } -} - -pub fn zip(args: Vec) -> EnvValue { - if args.len() != 2 { - panic!("zip espera exatamente dois argumentos"); - } - - if let (EnvValue::Exp(Expression::FuncCall(name1, lista1)), EnvValue::Exp(Expression::FuncCall(name2, lista2))) = (&args[0], &args[1]) { - let zipped_list: Vec = lista1.iter().zip(lista2.iter()) - .map(|(a, b)| Expression::FuncCall("pair".to_string(), vec![a.clone(), b.clone()])) - .collect(); - return EnvValue::Exp(Expression::FuncCall("zipped_list".to_string(), zipped_list)); - } else { - panic!("zip espera argumentos do tipo lista"); - } -} - -pub fn enumerate(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("enumerate espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { - let mut tupla = vec![]; - - // Iterar sobre a lista e criar tuplas (index, item) - for (index, item) in lista.iter().enumerate() { - if let Expression::CInt(val) = item { - tupla.push(Expression::FuncCall("pair".to_string(), vec![ - Expression::CInt(index as i32), - Expression::CInt(*val), - ])); - } else { - panic!("enumerate espera uma lista de inteiros"); - } - } - return EnvValue::Exp(Expression::FuncCall("tupla_list".to_string(), tupla)); - } else { - panic!("enumerate espera um argumento do tipo lista"); - } -} - -pub fn sort(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("sort espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { - let mut result: Vec = lista.clone(); - let len = result.len(); - - for i in 0..len { - for j in 0..len - i - 1 { - if let (Expression::CInt(val1), Expression::CInt(val2)) = (&result[j], &result[j + 1]) { - if val1 > val2 { - let temp = result[j].clone(); - result[j] = result[j + 1].clone(); - result[j + 1] = temp; - } - } else { - panic!("sort espera uma lista de inteiros"); - } - } - } - - return EnvValue::Exp(Expression::FuncCall(name.clone(), result)); - } else { - panic!("sort espera um argumento do tipo lista"); - } -} - -pub fn str_upper(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("str_upper expects exactly one argument"); - } - - if let EnvValue::Exp(Expression::CString(s)) = &args[0] { - EnvValue::Exp(Expression::CString(s.to_uppercase())) - } else { - panic!("str_upper expects a string argument"); - } -} - -pub fn str_lower(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("str_lower expects exactly one argument"); - } - if let EnvValue::Exp(Expression::CString(s)) = &args[0] { - EnvValue::Exp(Expression::CString(s.to_lowercase())) - } else { - panic!("str_lower expects a string argument"); - } -} - -pub fn str_length(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("str_length expects exactly one argument"); - } - if let EnvValue::Exp(Expression::CString(s)) = &args[0] { - EnvValue::Exp(Expression::CInt(s.chars().count() as i32)) - } else { - panic!("str_length expects a string argument"); - } -} - -pub fn str_reverse(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("str_reverse expects exactly one argument"); - } - if let EnvValue::Exp(Expression::CString(s)) = &args[0] { - EnvValue::Exp(Expression::CString(s.chars().rev().collect())) - } else { - panic!("str_reverse expects a string argument"); - } -} - -//conta quantas vezes aparece um char especifico -pub fn cont_chars(args: Vec) -> EnvValue { - if args.len() != 2 { - panic!("cont_chars expects exactly two arguments"); - } - if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = (&args[0], &args[1]) { - if c.len() != 1 { - panic!("cont_chars expects a single character as the second argument"); - } - let target = c.chars().next().unwrap(); - EnvValue::Exp(Expression::CInt(s.chars().filter(|&ch| ch == target).count() as i32)) - } else { - panic!("cont_chars expects a string and a character as arguments"); - } -} - -//retira todas as aparicoes de um char especifico -pub fn filter_out_char(args: Vec) -> EnvValue { - if args.len() != 2 { - panic!("filter_out_char expects exactly two arguments"); - } - if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = (&args[0], &args[1]) { - if c.len() != 1 { - panic!("filter_out_char expects a single character as the second argument"); - } - let target = c.chars().next().unwrap(); - EnvValue::Exp(Expression::CString(s.chars().filter(|&ch| ch != target).collect())) - } else { - panic!("filter_out_char expects a string and a character as arguments"); - } -} - -// substitui os N primeiros caracteres "old" por um novo caracter "new" -pub fn replace(args: Vec) -> EnvValue { - if args.len() < 3 || args.len() > 4 { - panic!("replace expects between 3 and 4 arguments"); - } - if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(old)), EnvValue::Exp(Expression::CString(new))) = (&args[0], &args[1], &args[2]) { - let count = if args.len() == 4 { - if let EnvValue::Exp(Expression::CInt(n)) = &args[3] { - *n - } else { - panic!("replace expects an integer as the fourth argument (count)"); - } - } else { - -1 - }; - - let result = if count < 0 { - s.replace(old, new) - } else { - let mut result = s.clone(); - let mut occurrences = 0; - while occurrences < count { - if let Some(pos) = result.find(old) { - result = format!("{}{}{}", &result[..pos], new, &result[pos + old.len()..]); - occurrences += 1; - } else { - break; - } - } - result - }; - - EnvValue::Exp(Expression::CString(result)) - } else { - panic!("replace expects three string arguments and an optional integer"); - } -} - -//centraliza a string e preenche o resto com um char -pub fn center(args: Vec) -> EnvValue { - if args.len() != 3 { - panic!("center expects exactly three arguments"); - } - - if let ( - EnvValue::Exp(Expression::CString(s)), - EnvValue::Exp(Expression::CInt(width)), - EnvValue::Exp(Expression::CString(fillchar)), - ) = (&args[0], &args[1], &args[2]) - { - if fillchar.len() != 1 { - panic!("center expects a single character as the fill character"); - } - - let fill = fillchar.chars().next().unwrap(); - let pad = (*width as usize).saturating_sub(s.len()); - let left = pad / 2; - let right = pad - left; - - let centered = format!( - "{}{}{}", - fill.to_string().repeat(left), - s, - fill.to_string().repeat(right) - ); - - EnvValue::Exp(Expression::FuncCall( - "center".to_string(), - vec![Expression::CString(centered)], - )) - } else { - panic!("center expects a string, an integer width, and a character as arguments"); - } -} - -//acha uma substring -pub fn find(args: Vec) -> EnvValue { - if args.len() < 2 || args.len() > 4 { - panic!("find expects between 2 and 4 arguments"); - } - - if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(sub))) = - (&args[0], &args[1]) - { - let start = if args.len() > 2 { - if let EnvValue::Exp(Expression::CInt(n)) = &args[2] { - *n as usize - } else { - panic!("find expects an integer as the third argument (start index)"); - } - } else { - 0 - }; - - let end = if args.len() > 3 { - if let EnvValue::Exp(Expression::CInt(n)) = &args[3] { - Some(*n as usize) - } else { - panic!("find expects an integer as the fourth argument (end index)"); - } - } else { - None - }; - - let end = end.unwrap_or(s.len()); - let result = match s.get(start..end) { - Some(substring) => substring.find(sub).map(|i| i + start), - None => None, - }; - - let retorno = match result { - Some(index) => EnvValue::Exp(Expression::CInt(index as i32)), - None => EnvValue::Exp(Expression::CInt(-1)), - }; - - if let EnvValue::Exp(expr) = retorno { - EnvValue::Exp(Expression::FuncCall("find".to_string(), vec![expr])) - } else { - panic!("invalid return value type"); - } - - } else { - panic!("find expects two strings as first arguments"); - } -} - -//recebe uma lista de strings e junta elas em uma string so -pub fn join(args: Vec) -> EnvValue { - if args.len() != 2 { - panic!("join expects exactly two arguments"); - } - - if let ( - EnvValue::Exp(Expression::CString(sep)), - EnvValue::Exp(Expression::FuncCall(_, lista)), - ) = (&args[0], &args[1]) - { - let strings: Vec = lista - .iter() - .map(|expr| { - if let Expression::CString(s) = expr { - s.clone() - } else { - panic!("join expects a list of strings as the second argument"); - } - }) - .collect(); - - EnvValue::Exp(Expression::CString(strings.join(sep))) - } else { - panic!("join expects a string and a list of strings as arguments"); - } -} - -pub fn partition(args: Vec) -> EnvValue { - if args.len() != 2 { - panic!("partition expects exactly two arguments"); - } - - if let ( - EnvValue::Exp(Expression::CString(s)), - EnvValue::Exp(Expression::CString(sep)), - ) = (&args[0], &args[1]) - { - match s.find(sep) { - Some(index) => EnvValue::Exp(Expression::FuncCall( - "tuple".to_string(), - vec![ - Expression::CString(s[..index].to_string()), - Expression::CString(sep.clone()), - Expression::CString(s[index + sep.len()..].to_string()), - ], - )), - None => EnvValue::Exp(Expression::FuncCall( - "tuple".to_string(), - vec![ - Expression::CString(s.to_string()), - Expression::CString(String::new()), - Expression::CString(String::new()), - ], - )), - } - } else { - panic!("partition expects two string arguments"); - } -} - pub fn factorial(args: Vec) -> EnvValue { if args.len() != 1 { panic!("factorial expects exactly one argument"); @@ -605,322 +143,9 @@ mod tests { } } - #[test] - fn test_len() { - let lista = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(3), - ]; - let result = len(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); - match result { - EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 3), - _ => panic!("Resultado incorreto para len([1, 2, 3])"), - } - } - - #[test] - fn test_max() { - let lista = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(5), - ]; - - let result = max(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); - - match result { - EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 5), - _ => panic!("Resultado incorreto para len([1, 2, 5])"), - } - } - - #[test] - fn test_min() { - let lista = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(5), - ]; - - let result = min(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); - - match result { - EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 1), - _ => panic!("Resultado incorreto para len([1, 2, 5])"), - } - } - - #[test] - fn test_index() { - let lista = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(5), - ]; - - let result = index(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))], 5); - - match result { - EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 2), // O índice do valor 5 é 2 - _ => panic!("Resultado incorreto para index([1, 2, 5], 5)"), - } - } - - - #[test] - fn test_remove() { - let lista = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(5), - ]; - - let result = remove(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))], 2); - - match result { - EnvValue::Exp(Expression::FuncCall(_, nova_lista)) => { - let expected = vec![ - Expression::CInt(1), - Expression::CInt(5), - ]; - assert_eq!(nova_lista, expected); - }, - _ => panic!("Resultado incorreto para remove([1, 2, 5], 2)"), - } - } - - #[test] - fn test_zip() { - let lista1 = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(3), - ]; - let lista2 = vec![ - Expression::CInt(4), - Expression::CInt(5), - Expression::CInt(6), - ]; - - let result = zip(vec![ - EnvValue::Exp(Expression::FuncCall("lista1".to_string(), lista1)), - EnvValue::Exp(Expression::FuncCall("lista2".to_string(), lista2)) - ]); - - match result { - EnvValue::Exp(Expression::FuncCall(_, zipped_list)) => { - let expected = vec![ - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(1), Expression::CInt(4)]), - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(2), Expression::CInt(5)]), - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(3), Expression::CInt(6)]), - ]; - assert_eq!(zipped_list, expected); - }, - _ => panic!("Resultado incorreto para zip([1, 2, 3], [4, 5, 6])"), - } - } - - #[test] - fn test_enumerate() { - let lista = vec![ - Expression::CInt(10), - Expression::CInt(20), - Expression::CInt(30), - ]; - - let result = enumerate(vec![EnvValue::Exp(Expression::FuncCall("lista".to_string(), lista))]); - - match result { - EnvValue::Exp(Expression::FuncCall(_, tupla_list)) => { - let expected = vec![ - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(0), Expression::CInt(10)]), - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(1), Expression::CInt(20)]), - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(2), Expression::CInt(30)]), - ]; - assert_eq!(tupla_list, expected); - }, - _ => panic!("Resultado incorreto para enumerate([10, 20, 30])"), - } - } - - #[test] - fn test_sort() { - let lista = vec![ - Expression::CInt(3), - Expression::CInt(1), - Expression::CInt(4), - Expression::CInt(1), - Expression::CInt(5), - Expression::CInt(9), - Expression::CInt(2), - Expression::CInt(6), - Expression::CInt(5), - ]; - - let result = sort(vec![EnvValue::Exp(Expression::FuncCall("lista".to_string(), lista))]); - - match result { - EnvValue::Exp(Expression::FuncCall(_, sorted_list)) => { - let expected = vec![ - Expression::CInt(1), - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(3), - Expression::CInt(4), - Expression::CInt(5), - Expression::CInt(5), - Expression::CInt(6), - Expression::CInt(9), - ]; - assert_eq!(sorted_list, expected); - }, - _ => panic!("Resultado incorreto para sort([3, 1, 4, 1, 5, 9, 2, 6, 5])"), - } - } - #[test] - fn test_str_lower_valid_strings() { - let result = str_lower(vec![EnvValue::Exp(Expression::CString(String::from("HELLO")))]); - match result { - EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "hello"), - _ => panic!("Incorrect result for str_lower('HELLO')"), - } - } - - #[test] - fn test_str_length_valid_string() { - let result = str_length(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); - match result { - EnvValue::Exp(Expression::CInt(len)) => assert_eq!(len, 5), - _ => panic!("Incorrect result for str_length('hello')"), - } - } - - #[test] - fn test_str_reverse_valid_string() { - let result = str_reverse(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); - match result { - EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "olleh"), - _ => panic!("Incorrect result for str_reverse('hello')"), - } - } - - #[test] - fn test_cont_chars_valid_input() { - let result = cont_chars(vec![ - EnvValue::Exp(Expression::CString(String::from("banana"))), - EnvValue::Exp(Expression::CString(String::from("a"))), - ]); - match result { - EnvValue::Exp(Expression::CInt(count)) => assert_eq!(count, 3), - _ => panic!("Incorrect result for cont_chars('banana', 'a')"), - } - } - - #[test] - fn test_filter_out_char_valid_input() { - let result = filter_out_char(vec![ - EnvValue::Exp(Expression::CString(String::from("banana"))), - EnvValue::Exp(Expression::CString(String::from("a"))), - ]); - match result { - EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "bnn"), - _ => panic!("Incorrect result for filter_out_char('banana', 'a')"), - } - } - - #[test] - fn test_replace_valid_input() { - let result = replace(vec![ - EnvValue::Exp(Expression::CString(String::from("banana"))), - EnvValue::Exp(Expression::CString(String::from("a"))), - EnvValue::Exp(Expression::CString(String::from("o"))), - ]); - match result { - EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "bonono"), - _ => panic!("Incorrect result for replace('banana', 'a', 'o')"), - } - } - - #[test] - fn test_center_valid_input() { - let result = center(vec![ - EnvValue::Exp(Expression::CString(String::from("hello"))), - EnvValue::Exp(Expression::CInt(11)), - EnvValue::Exp(Expression::CString(String::from("*"))), - ]); - match result { - EnvValue::Exp(Expression::FuncCall(_, args)) => { - if let Expression::CString(centered) = &args[0] { - assert_eq!(centered, "***hello***"); - } else { - panic!("Incorrect result for center('hello', 11, '*')"); - } - } - _ => panic!("Incorrect return type for center"), - } - } - - #[test] - fn test_find_valid_input() { - let result = find(vec![ - EnvValue::Exp(Expression::CString(String::from("hello world"))), - EnvValue::Exp(Expression::CString(String::from("world"))), - ]); - match result { - EnvValue::Exp(Expression::FuncCall(_, args)) => { - if let Expression::CInt(index) = &args[0] { - assert_eq!(*index, 6); - } else { - panic!("Incorrect result for find('hello world', 'world')"); - } - } - _ => panic!("Incorrect return type for find"), - } - } - - #[test] - fn test_join_valid_input() { - let result = join(vec![ - EnvValue::Exp(Expression::CString(String::from(","))), - EnvValue::Exp(Expression::FuncCall( - "list".to_string(), - vec![ - Expression::CString(String::from("a")), - Expression::CString(String::from("b")), - Expression::CString(String::from("c")), - ], - )), - ]); - match result { - EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "a,b,c"), - _ => panic!("Incorrect result for join(',', ['a', 'b', 'c'])"), - } - } - - #[test] - fn test_partition_valid_input() { - let result = partition(vec![ - EnvValue::Exp(Expression::CString(String::from("banana"))), - EnvValue::Exp(Expression::CString(String::from("n"))), - ]); - match result { - EnvValue::Exp(Expression::FuncCall(_, args)) => { - if let (Expression::CString(left), Expression::CString(sep), Expression::CString(right)) = (&args[0], &args[1], &args[2]) { - assert_eq!(left, "ba"); - assert_eq!(sep, "n"); - assert_eq!(right, "ana"); - } else { - panic!("Incorrect result for partition('banana', 'n')"); - } - } - _ => panic!("Incorrect return type for partition"), - } - } - #[test] fn test_sqrt_zero() { let result = sqrt(vec![EnvValue::Exp(Expression::CReal(0.0))]); diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs new file mode 100644 index 0000000..d735b12 --- /dev/null +++ b/src/stdlib/string.rs @@ -0,0 +1,410 @@ +use crate::ir::ast::{EnvValue, Expression}; +use crate::ir::ast::Environment; +use std::collections::HashMap; + +pub fn str_upper(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("str_upper expects exactly one argument"); + } + + if let EnvValue::Exp(Expression::CString(s)) = &args[0] { + EnvValue::Exp(Expression::CString(s.to_uppercase())) + } else { + panic!("str_upper expects a string argument"); + } +} + +pub fn str_lower(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("str_lower expects exactly one argument"); + } + if let EnvValue::Exp(Expression::CString(s)) = &args[0] { + EnvValue::Exp(Expression::CString(s.to_lowercase())) + } else { + panic!("str_lower expects a string argument"); + } +} + +pub fn str_length(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("str_length expects exactly one argument"); + } + if let EnvValue::Exp(Expression::CString(s)) = &args[0] { + EnvValue::Exp(Expression::CInt(s.chars().count() as i32)) + } else { + panic!("str_length expects a string argument"); + } +} + +pub fn str_reverse(args: Vec) -> EnvValue { + if args.len() != 1 { + panic!("str_reverse expects exactly one argument"); + } + if let EnvValue::Exp(Expression::CString(s)) = &args[0] { + EnvValue::Exp(Expression::CString(s.chars().rev().collect())) + } else { + panic!("str_reverse expects a string argument"); + } +} + +//conta quantas vezes aparece um char especifico +pub fn cont_chars(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("cont_chars expects exactly two arguments"); + } + if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = (&args[0], &args[1]) { + if c.len() != 1 { + panic!("cont_chars expects a single character as the second argument"); + } + let target = c.chars().next().unwrap(); + EnvValue::Exp(Expression::CInt(s.chars().filter(|&ch| ch == target).count() as i32)) + } else { + panic!("cont_chars expects a string and a character as arguments"); + } +} + +//retira todas as aparicoes de um char especifico +pub fn filter_out_char(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("filter_out_char expects exactly two arguments"); + } + if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = (&args[0], &args[1]) { + if c.len() != 1 { + panic!("filter_out_char expects a single character as the second argument"); + } + let target = c.chars().next().unwrap(); + EnvValue::Exp(Expression::CString(s.chars().filter(|&ch| ch != target).collect())) + } else { + panic!("filter_out_char expects a string and a character as arguments"); + } +} + +// substitui os N primeiros caracteres "old" por um novo caracter "new" +pub fn replace(args: Vec) -> EnvValue { + if args.len() < 3 || args.len() > 4 { + panic!("replace expects between 3 and 4 arguments"); + } + if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(old)), EnvValue::Exp(Expression::CString(new))) = (&args[0], &args[1], &args[2]) { + let count = if args.len() == 4 { + if let EnvValue::Exp(Expression::CInt(n)) = &args[3] { + *n + } else { + panic!("replace expects an integer as the fourth argument (count)"); + } + } else { + -1 + }; + + let result = if count < 0 { + s.replace(old, new) + } else { + let mut result = s.clone(); + let mut occurrences = 0; + while occurrences < count { + if let Some(pos) = result.find(old) { + result = format!("{}{}{}", &result[..pos], new, &result[pos + old.len()..]); + occurrences += 1; + } else { + break; + } + } + result + }; + + EnvValue::Exp(Expression::CString(result)) + } else { + panic!("replace expects three string arguments and an optional integer"); + } +} + +//centraliza a string e preenche o resto com um char +pub fn center(args: Vec) -> EnvValue { + if args.len() != 3 { + panic!("center expects exactly three arguments"); + } + + if let ( + EnvValue::Exp(Expression::CString(s)), + EnvValue::Exp(Expression::CInt(width)), + EnvValue::Exp(Expression::CString(fillchar)), + ) = (&args[0], &args[1], &args[2]) + { + if fillchar.len() != 1 { + panic!("center expects a single character as the fill character"); + } + + let fill = fillchar.chars().next().unwrap(); + let pad = (*width as usize).saturating_sub(s.len()); + let left = pad / 2; + let right = pad - left; + + let centered = format!( + "{}{}{}", + fill.to_string().repeat(left), + s, + fill.to_string().repeat(right) + ); + + EnvValue::Exp(Expression::FuncCall( + "center".to_string(), + vec![Expression::CString(centered)], + )) + } else { + panic!("center expects a string, an integer width, and a character as arguments"); + } +} + +//acha uma substring +pub fn find(args: Vec) -> EnvValue { + if args.len() < 2 || args.len() > 4 { + panic!("find expects between 2 and 4 arguments"); + } + + if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(sub))) = + (&args[0], &args[1]) + { + let start = if args.len() > 2 { + if let EnvValue::Exp(Expression::CInt(n)) = &args[2] { + *n as usize + } else { + panic!("find expects an integer as the third argument (start index)"); + } + } else { + 0 + }; + + let end = if args.len() > 3 { + if let EnvValue::Exp(Expression::CInt(n)) = &args[3] { + Some(*n as usize) + } else { + panic!("find expects an integer as the fourth argument (end index)"); + } + } else { + None + }; + + let end = end.unwrap_or(s.len()); + let result = match s.get(start..end) { + Some(substring) => substring.find(sub).map(|i| i + start), + None => None, + }; + + let retorno = match result { + Some(index) => EnvValue::Exp(Expression::CInt(index as i32)), + None => EnvValue::Exp(Expression::CInt(-1)), + }; + + if let EnvValue::Exp(expr) = retorno { + EnvValue::Exp(Expression::FuncCall("find".to_string(), vec![expr])) + } else { + panic!("invalid return value type"); + } + + } else { + panic!("find expects two strings as first arguments"); + } +} + +//recebe uma lista de strings e junta elas em uma string so +pub fn join(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("join expects exactly two arguments"); + } + + if let ( + EnvValue::Exp(Expression::CString(sep)), + EnvValue::Exp(Expression::FuncCall(_, lista)), + ) = (&args[0], &args[1]) + { + let strings: Vec = lista + .iter() + .map(|expr| { + if let Expression::CString(s) = expr { + s.clone() + } else { + panic!("join expects a list of strings as the second argument"); + } + }) + .collect(); + + EnvValue::Exp(Expression::CString(strings.join(sep))) + } else { + panic!("join expects a string and a list of strings as arguments"); + } +} + +pub fn partition(args: Vec) -> EnvValue { + if args.len() != 2 { + panic!("partition expects exactly two arguments"); + } + + if let ( + EnvValue::Exp(Expression::CString(s)), + EnvValue::Exp(Expression::CString(sep)), + ) = (&args[0], &args[1]) + { + match s.find(sep) { + Some(index) => EnvValue::Exp(Expression::FuncCall( + "tuple".to_string(), + vec![ + Expression::CString(s[..index].to_string()), + Expression::CString(sep.clone()), + Expression::CString(s[index + sep.len()..].to_string()), + ], + )), + None => EnvValue::Exp(Expression::FuncCall( + "tuple".to_string(), + vec![ + Expression::CString(s.to_string()), + Expression::CString(String::new()), + Expression::CString(String::new()), + ], + )), + } + } else { + panic!("partition expects two string arguments"); + } +} +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_str_lower_valid_strings() { + let result = str_lower(vec![EnvValue::Exp(Expression::CString(String::from("HELLO")))]); + match result { + EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "hello"), + _ => panic!("Incorrect result for str_lower('HELLO')"), + } + } + + #[test] + fn test_str_length_valid_string() { + let result = str_length(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); + match result { + EnvValue::Exp(Expression::CInt(len)) => assert_eq!(len, 5), + _ => panic!("Incorrect result for str_length('hello')"), + } + } + + #[test] + fn test_str_reverse_valid_string() { + let result = str_reverse(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); + match result { + EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "olleh"), + _ => panic!("Incorrect result for str_reverse('hello')"), + } + } + + #[test] + fn test_cont_chars_valid_input() { + let result = cont_chars(vec![ + EnvValue::Exp(Expression::CString(String::from("banana"))), + EnvValue::Exp(Expression::CString(String::from("a"))), + ]); + match result { + EnvValue::Exp(Expression::CInt(count)) => assert_eq!(count, 3), + _ => panic!("Incorrect result for cont_chars('banana', 'a')"), + } + } + + #[test] + fn test_filter_out_char_valid_input() { + let result = filter_out_char(vec![ + EnvValue::Exp(Expression::CString(String::from("banana"))), + EnvValue::Exp(Expression::CString(String::from("a"))), + ]); + match result { + EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "bnn"), + _ => panic!("Incorrect result for filter_out_char('banana', 'a')"), + } + } + + #[test] + fn test_replace_valid_input() { + let result = replace(vec![ + EnvValue::Exp(Expression::CString(String::from("banana"))), + EnvValue::Exp(Expression::CString(String::from("a"))), + EnvValue::Exp(Expression::CString(String::from("o"))), + ]); + match result { + EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "bonono"), + _ => panic!("Incorrect result for replace('banana', 'a', 'o')"), + } + } + + #[test] + fn test_center_valid_input() { + let result = center(vec![ + EnvValue::Exp(Expression::CString(String::from("hello"))), + EnvValue::Exp(Expression::CInt(11)), + EnvValue::Exp(Expression::CString(String::from("*"))), + ]); + match result { + EnvValue::Exp(Expression::FuncCall(_, args)) => { + if let Expression::CString(centered) = &args[0] { + assert_eq!(centered, "***hello***"); + } else { + panic!("Incorrect result for center('hello', 11, '*')"); + } + } + _ => panic!("Incorrect return type for center"), + } + } + + #[test] + fn test_find_valid_input() { + let result = find(vec![ + EnvValue::Exp(Expression::CString(String::from("hello world"))), + EnvValue::Exp(Expression::CString(String::from("world"))), + ]); + match result { + EnvValue::Exp(Expression::FuncCall(_, args)) => { + if let Expression::CInt(index) = &args[0] { + assert_eq!(*index, 6); + } else { + panic!("Incorrect result for find('hello world', 'world')"); + } + } + _ => panic!("Incorrect return type for find"), + } + } + + #[test] + fn test_join_valid_input() { + let result = join(vec![ + EnvValue::Exp(Expression::CString(String::from(","))), + EnvValue::Exp(Expression::FuncCall( + "list".to_string(), + vec![ + Expression::CString(String::from("a")), + Expression::CString(String::from("b")), + Expression::CString(String::from("c")), + ], + )), + ]); + match result { + EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "a,b,c"), + _ => panic!("Incorrect result for join(',', ['a', 'b', 'c'])"), + } + } + + #[test] + fn test_partition_valid_input() { + let result = partition(vec![ + EnvValue::Exp(Expression::CString(String::from("banana"))), + EnvValue::Exp(Expression::CString(String::from("n"))), + ]); + match result { + EnvValue::Exp(Expression::FuncCall(_, args)) => { + if let (Expression::CString(left), Expression::CString(sep), Expression::CString(right)) = (&args[0], &args[1], &args[2]) { + assert_eq!(left, "ba"); + assert_eq!(sep, "n"); + assert_eq!(right, "ana"); + } else { + panic!("Incorrect result for partition('banana', 'n')"); + } + } + _ => panic!("Incorrect return type for partition"), + } + } +} \ No newline at end of file From 4cae49176c710016213c6c3dbe5dacd29c5df406 Mon Sep 17 00:00:00 2001 From: Layr Date: Sun, 16 Feb 2025 10:43:27 -0300 Subject: [PATCH 09/15] Tratamento de erros com Result<> --- src/interpreter/interpreter.rs | 20 +- src/ir/ast.rs | 4 +- src/stdlib.rs | 1 - src/stdlib/list.rs | 382 --------------------- src/stdlib/math.rs | 610 +++++++++++++++++++++++---------- src/stdlib/string.rs | 2 - src/tc/type_checker.rs | 23 +- 7 files changed, 464 insertions(+), 578 deletions(-) delete mode 100644 src/stdlib/list.rs diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 8185272..cbbfc57 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -131,10 +131,16 @@ pub fn execute( args_values.push(env_value); } + let result_value = f(args_values)?; - let result_value = f(args_values); + if get_type_env_value(&result_value) != return_type { + return Err(format!( + "Mismatched types: expected {:?}, but the function returned {:?}", + return_type, + get_type_env_value(&result_value) + )); + } - new_env.insert( "metaResult".to_string(), (Some(result_value.clone()), return_type.clone()), @@ -447,7 +453,7 @@ fn lte(lhs: Expression, rhs: Expression, env: &Environment) -> Result) -> EnvValue, + f: fn(Vec) -> Result, args: Vec, return_type: Type, env: &Environment, @@ -459,7 +465,7 @@ fn meta( args_values.push(env_value); } - let result_value = f(args_values); + let result_value = f(args_values)?; if get_type_env_value(&result_value) != return_type { return Err(format!( @@ -492,8 +498,7 @@ mod tests { use crate::ir::ast::Statement::*; use crate::ir::ast::Type::*; use crate::stdlib::math::{sqrt, gcd}; - use crate::stdlib::string::{str_upper}; - use crate::stdlib::list::{len}; + //use crate::stdlib::string::{str_upper}; use approx::relative_eq; @@ -1385,6 +1390,7 @@ mod tests { } } + /* #[test] fn metastmt_function_upper(){ /* @@ -1450,5 +1456,5 @@ mod tests { } } - + */ } diff --git a/src/ir/ast.rs b/src/ir/ast.rs index 766bb6d..4c914ec 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -43,7 +43,7 @@ pub enum Expression { /* function call */ FuncCall(Name, Vec), - MetaExp(fn(Vec) -> EnvValue, Vec, Type), + MetaExp(fn(Vec) -> Result, Vec, Type), /* arithmetic expressions over numbers */ Add(Box, Box), @@ -75,7 +75,7 @@ pub enum Statement { Sequence(Box, Box), FuncDef(Name, Function), Return(Box), - MetaStmt(fn(Vec) -> EnvValue, Vec, Type), + MetaStmt(fn(Vec) -> Result, Vec, Type), } #[derive(Debug)] diff --git a/src/stdlib.rs b/src/stdlib.rs index 1d02495..73beb73 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -1,3 +1,2 @@ pub mod math; -pub mod list; pub mod string; \ No newline at end of file diff --git a/src/stdlib/list.rs b/src/stdlib/list.rs deleted file mode 100644 index 09103b8..0000000 --- a/src/stdlib/list.rs +++ /dev/null @@ -1,382 +0,0 @@ -use crate::ir::ast::{EnvValue, Expression}; -use crate::ir::ast::Environment; -use std::collections::HashMap; - -pub fn len(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("len espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { - let mut contador = 0; - for _ in lista { - contador += 1; - } - return EnvValue::Exp(Expression::CInt(contador as i32)); - } else { - panic!("len espera um argumento do tipo lista"); - } -} - -pub fn max(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("max espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { - - - // Inicializar o valor máximo com o primeiro elemento da lista - let mut achei_max = match lista[0] { - Expression::CInt(val) => val, - _ => panic!("max espera uma lista de inteiros"), - }; - - // Iterar sobre a lista e encontrar o valor máximo - for expr in &lista[1..] { - if let Expression::CInt(val) = expr { - if *val > achei_max { - achei_max = *val; // Atualiza achei_max com o valor do inteiro - } - } else { - panic!("max espera uma lista de inteiros"); - } - } - - return EnvValue::Exp(Expression::CInt(achei_max)); - } else { - panic!("max espera um argumento do tipo lista"); - } -} - -pub fn min(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("max espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { - - - // Inicializar o valor máximo com o primeiro elemento da lista - let mut achei_min = match lista[0] { - Expression::CInt(val) => val, - _ => panic!("min espera uma lista de inteiros"), - }; - - // Iterar sobre a lista e encontrar o valor máximo - for expr in &lista[1..] { - if let Expression::CInt(val) = expr { - if *val == achei_min { - achei_min = *val; // Atualiza achei_max com o valor do inteiro - } - } else { - panic!("min espera uma lista de inteiros"); - } - } - - return EnvValue::Exp(Expression::CInt(achei_min)); - } else { - panic!("min espera um argumento do tipo lista"); - } -} - -pub fn index(args: Vec, target: i32) -> EnvValue { - if args.len() != 1 { - panic!("index espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(_, lista)) = &args[0] { - let mut contador = 0; - - // Iterar sobre a lista e encontrar o índice - for expr in lista { - if let Expression::CInt(val) = expr { - if *val == target { - return EnvValue::Exp(Expression::CInt(contador)); - } - contador +=1; - } else { - panic!("index espera uma lista de inteiros"); - } - } - return EnvValue::Exp(Expression::CInt(-1)); - - } else { - panic!("index espera um argumento do tipo lista"); - } -} - -pub fn remove(args: Vec, target: i32) -> EnvValue { - if args.len() != 1 { - panic!("remove espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { - let mut lista_nova = vec![]; - - // Iterar sobre a lista e remover o valor alvo (target) - for expr in lista { - if let Expression::CInt(val) = expr { - if *val != target { - lista_nova.push(Expression::CInt(*val)); - } - } else { - panic!("remove espera uma lista de inteiros"); - } - } - - return EnvValue::Exp(Expression::FuncCall(name.clone(), lista_nova)); - } else { - panic!("remove espera um argumento do tipo lista"); - } -} - -pub fn zip(args: Vec) -> EnvValue { - if args.len() != 2 { - panic!("zip espera exatamente dois argumentos"); - } - - if let (EnvValue::Exp(Expression::FuncCall(name1, lista1)), EnvValue::Exp(Expression::FuncCall(name2, lista2))) = (&args[0], &args[1]) { - let zipped_list: Vec = lista1.iter().zip(lista2.iter()) - .map(|(a, b)| Expression::FuncCall("pair".to_string(), vec![a.clone(), b.clone()])) - .collect(); - return EnvValue::Exp(Expression::FuncCall("zipped_list".to_string(), zipped_list)); - } else { - panic!("zip espera argumentos do tipo lista"); - } -} - -pub fn enumerate(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("enumerate espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { - let mut tupla = vec![]; - - // Iterar sobre a lista e criar tuplas (index, item) - for (index, item) in lista.iter().enumerate() { - if let Expression::CInt(val) = item { - tupla.push(Expression::FuncCall("pair".to_string(), vec![ - Expression::CInt(index as i32), - Expression::CInt(*val), - ])); - } else { - panic!("enumerate espera uma lista de inteiros"); - } - } - return EnvValue::Exp(Expression::FuncCall("tupla_list".to_string(), tupla)); - } else { - panic!("enumerate espera um argumento do tipo lista"); - } -} - -pub fn sort(args: Vec) -> EnvValue { - if args.len() != 1 { - panic!("sort espera exatamente um argumento"); - } - - if let EnvValue::Exp(Expression::FuncCall(name, lista)) = &args[0] { - let mut result: Vec = lista.clone(); - let len = result.len(); - - for i in 0..len { - for j in 0..len - i - 1 { - if let (Expression::CInt(val1), Expression::CInt(val2)) = (&result[j], &result[j + 1]) { - if val1 > val2 { - let temp = result[j].clone(); - result[j] = result[j + 1].clone(); - result[j + 1] = temp; - } - } else { - panic!("sort espera uma lista de inteiros"); - } - } - } - - return EnvValue::Exp(Expression::FuncCall(name.clone(), result)); - } else { - panic!("sort espera um argumento do tipo lista"); - } -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_len() { - let lista = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(3), - ]; - - let result = len(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); - - match result { - EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 3), - _ => panic!("Resultado incorreto para len([1, 2, 3])"), - } - } - - #[test] - fn test_max() { - let lista = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(5), - ]; - - let result = max(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); - - match result { - EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 5), - _ => panic!("Resultado incorreto para len([1, 2, 5])"), - } - } - - #[test] - fn test_min() { - let lista = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(5), - ]; - - let result = min(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))]); - - match result { - EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 1), - _ => panic!("Resultado incorreto para len([1, 2, 5])"), - } - } - - #[test] - fn test_index() { - let lista = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(5), - ]; - - let result = index(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))], 5); - - match result { - EnvValue::Exp(Expression::CInt(res_value)) => assert_eq!(res_value, 2), // O índice do valor 5 é 2 - _ => panic!("Resultado incorreto para index([1, 2, 5], 5)"), - } - } - - - #[test] - fn test_remove() { - let lista = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(5), - ]; - - let result = remove(vec![EnvValue::Exp(Expression::FuncCall("test".to_string(), lista))], 2); - - match result { - EnvValue::Exp(Expression::FuncCall(_, nova_lista)) => { - let expected = vec![ - Expression::CInt(1), - Expression::CInt(5), - ]; - assert_eq!(nova_lista, expected); - }, - _ => panic!("Resultado incorreto para remove([1, 2, 5], 2)"), - } - } - - #[test] - fn test_zip() { - let lista1 = vec![ - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(3), - ]; - let lista2 = vec![ - Expression::CInt(4), - Expression::CInt(5), - Expression::CInt(6), - ]; - - let result = zip(vec![ - EnvValue::Exp(Expression::FuncCall("lista1".to_string(), lista1)), - EnvValue::Exp(Expression::FuncCall("lista2".to_string(), lista2)) - ]); - - match result { - EnvValue::Exp(Expression::FuncCall(_, zipped_list)) => { - let expected = vec![ - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(1), Expression::CInt(4)]), - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(2), Expression::CInt(5)]), - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(3), Expression::CInt(6)]), - ]; - assert_eq!(zipped_list, expected); - }, - _ => panic!("Resultado incorreto para zip([1, 2, 3], [4, 5, 6])"), - } - } - - #[test] - fn test_enumerate() { - let lista = vec![ - Expression::CInt(10), - Expression::CInt(20), - Expression::CInt(30), - ]; - - let result = enumerate(vec![EnvValue::Exp(Expression::FuncCall("lista".to_string(), lista))]); - - match result { - EnvValue::Exp(Expression::FuncCall(_, tupla_list)) => { - let expected = vec![ - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(0), Expression::CInt(10)]), - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(1), Expression::CInt(20)]), - Expression::FuncCall("pair".to_string(), vec![Expression::CInt(2), Expression::CInt(30)]), - ]; - assert_eq!(tupla_list, expected); - }, - _ => panic!("Resultado incorreto para enumerate([10, 20, 30])"), - } - } - - #[test] - fn test_sort() { - let lista = vec![ - Expression::CInt(3), - Expression::CInt(1), - Expression::CInt(4), - Expression::CInt(1), - Expression::CInt(5), - Expression::CInt(9), - Expression::CInt(2), - Expression::CInt(6), - Expression::CInt(5), - ]; - - let result = sort(vec![EnvValue::Exp(Expression::FuncCall("lista".to_string(), lista))]); - - match result { - EnvValue::Exp(Expression::FuncCall(_, sorted_list)) => { - let expected = vec![ - Expression::CInt(1), - Expression::CInt(1), - Expression::CInt(2), - Expression::CInt(3), - Expression::CInt(4), - Expression::CInt(5), - Expression::CInt(5), - Expression::CInt(6), - Expression::CInt(9), - ]; - assert_eq!(sorted_list, expected); - }, - _ => panic!("Resultado incorreto para sort([3, 1, 4, 1, 5, 9, 2, 6, 5])"), - } - } - -} \ No newline at end of file diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs index 9d08e36..9483697 100644 --- a/src/stdlib/math.rs +++ b/src/stdlib/math.rs @@ -1,42 +1,42 @@ use crate::ir::ast::{EnvValue, Expression}; -use crate::ir::ast::Environment; -use std::collections::HashMap; -pub fn sqrt(args: Vec) -> EnvValue { + +pub fn sqrt(args: Vec) -> Result { if args.len() != 1 { - panic!("sqrt expects exactly one argument"); + return Err("sqrt expects exactly one argument".to_string()); } if let EnvValue::Exp(Expression::CReal(x)) = &args[0] { - EnvValue::Exp(Expression::CReal(x.sqrt())) + Ok(EnvValue::Exp(Expression::CReal(x.sqrt()))) } else { - panic!("sqrt expects a real number argument"); + Err("sqrt expects a real number argument".to_string()) } } -pub fn factorial(args: Vec) -> EnvValue { +pub fn factorial(args: Vec) -> Result { if args.len() != 1 { - panic!("factorial expects exactly one argument"); + return Err("factorial expects exactly one argument".to_string()); } + if let EnvValue::Exp(Expression::CInt(n)) = &args[0] { if *n < 0 { - panic!("factorial expects a non-negative integer argument"); + return Err("factorial expects a non-negative integer argument".to_string()); } let mut prod: i32 = 1; for i in 1..=*n { prod *= i; } - EnvValue::Exp(Expression::CInt(prod)) + Ok(EnvValue::Exp(Expression::CInt(prod))) } else { - panic!("factorial expects a integer argument"); + Err("factorial expects an integer argument".to_string()) } } - -pub fn gcd(args: Vec) -> EnvValue { +pub fn gcd(args: Vec) -> Result { if args.len() != 2 { - panic!("gcd expects exactly two arguments"); + return Err("gcd expects exactly two arguments".to_string()); } + if let (EnvValue::Exp(Expression::CInt(a)), EnvValue::Exp(Expression::CInt(b))) = (&args[0], &args[1]) { @@ -47,385 +47,647 @@ pub fn gcd(args: Vec) -> EnvValue { b = a % b; a = t; } - EnvValue::Exp(Expression::CInt(a.abs())) + Ok(EnvValue::Exp(Expression::CInt(a.abs()))) } else { - panic!("gcd expects two integer arguments"); + Err("gcd expects two integer arguments".to_string()) } } -pub fn lcm(args: Vec) -> EnvValue { + +pub fn lcm(args: Vec) -> Result { if args.len() != 2 { - panic!("lcm expects exactly two arguments"); + return Err("lcm expects exactly two arguments".to_string()); } + if let (EnvValue::Exp(Expression::CInt(a)), EnvValue::Exp(Expression::CInt(b))) = (&args[0], &args[1]) { let gcd_val = match gcd(args.clone()) { - EnvValue::Exp(Expression::CInt(val)) => val, - _ => panic!("Error calculating gcd"), + Ok(EnvValue::Exp(Expression::CInt(val))) => val, + Err(err) => return Err(format!("Error calculating gcd: {}", err)), + _ => return Err("Unexpected error in gcd calculation".to_string()), }; - + let lcm_val = (a * b).abs() / gcd_val; - EnvValue::Exp(Expression::CInt(lcm_val)) + Ok(EnvValue::Exp(Expression::CInt(lcm_val))) } else { - panic!("lcm expects two integer arguments"); + Err("lcm expects two integer arguments".to_string()) } } -pub fn comb(args: Vec) -> EnvValue { +pub fn comb(args: Vec) -> Result { if args.len() != 2 { - panic!("comb expects exactly two arguments"); + return Err("comb expects exactly two arguments".to_string()); } + if let (EnvValue::Exp(Expression::CInt(n)), EnvValue::Exp(Expression::CInt(k))) = (&args[0], &args[1]) { if *n < 0 || *k < 0 { - panic!("comb expects non-negative integers"); + return Err("comb expects non-negative integers".to_string()); } let n = *n; let mut k = *k; if k > n { - return EnvValue::Exp(Expression::CInt(0)); + return Ok(EnvValue::Exp(Expression::CInt(0))); } if k > n - k { k = n - k; } let result = (0..k).fold(1, |acc, i| acc * (n - i) / (i + 1)); - EnvValue::Exp(Expression::CInt(result)) + Ok(EnvValue::Exp(Expression::CInt(result))) } else { - panic!("comb expects two integer arguments"); + Err("comb expects two integer arguments".to_string()) } } -pub fn perm(args: Vec) -> EnvValue { +pub fn perm(args: Vec) -> Result { if args.len() != 2 { - panic!("perm expects exactly two arguments"); + return Err("perm expects exactly two arguments".to_string()); } + if let (EnvValue::Exp(Expression::CInt(n)), EnvValue::Exp(Expression::CInt(k))) = (&args[0], &args[1]) { if *n < 0 || *k < 0 { - panic!("perm expects non-negative integers"); + return Err("perm expects non-negative integers".to_string()); } let n = *n; let k = *k; if k > n { - return EnvValue::Exp(Expression::CInt(0)); + return Ok(EnvValue::Exp(Expression::CInt(0))); } let mut result: i32 = 1; for i in 0..k { result *= n - i; } - EnvValue::Exp(Expression::CInt(result)) + Ok(EnvValue::Exp(Expression::CInt(result))) } else { - panic!("perm expects two integer arguments"); + Err("perm expects two integer arguments".to_string()) } } +pub fn is_prime(args: Vec) -> Result { + if args.len() != 1 { + return Err("is_prime expects exactly one argument".to_string()); + } + + if let EnvValue::Exp(Expression::CInt(n)) = &args[0] { + if *n < 0 { + return Err("is_prime expects a non-negative integer".to_string()); + } + let n = *n; + let result = { + if n <= 1 { + false + } else if n <= 3 { + true + } else if n % 2 == 0 || n % 3 == 0 { + false + } else { + let mut i = 5; + let mut prime = true; + while i * i <= n { + if n % i == 0 || n % (i + 2) == 0 { + prime = false; + break; + } + i += 6; + } + prime + } + }; + if result { + Ok(EnvValue::Exp(Expression::CTrue)) + } else { + Ok(EnvValue::Exp(Expression::CFalse)) + } + } else { + Err("is_prime expects an integer argument".to_string()) + } +} + + +pub fn log(args: Vec) -> Result { + if args.len() != 2 { + return Err("log expects exactly two arguments".to_string()); + } + if let (EnvValue::Exp(Expression::CReal(base)), EnvValue::Exp(Expression::CReal(x))) = + (&args[0], &args[1]) + { + Ok(EnvValue::Exp(Expression::CReal(x.log(*base)))) + } else { + Err("log expects two real arguments".to_string()) + } +} + + #[cfg(test)] mod tests { use super::*; +//TESTES FUNCAO SQRT #[test] fn test_sqrt_positive_real() { let result = sqrt(vec![EnvValue::Exp(Expression::CReal(9.0))]); - match result { - EnvValue::Exp(Expression::CReal(res_value)) => assert_eq!(res_value, 3.0), - _ => panic!("Incorrect result for sqrt of 9.0"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CReal(res_value))) = result { + assert_eq!(res_value, 3.0); } - + let result = sqrt(vec![EnvValue::Exp(Expression::CReal(49.0))]); - match result { - EnvValue::Exp(Expression::CReal(res_value)) => assert_eq!(res_value, 7.0), - _ => panic!("Incorrect result for sqrt of 49.0"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CReal(res_value))) = result { + assert_eq!(res_value, 7.0); } let result = sqrt(vec![EnvValue::Exp(Expression::CReal(121.0))]); - match result { - EnvValue::Exp(Expression::CReal(res_value)) => assert_eq!(res_value, 11.0), - _ => panic!("Incorrect result for sqrt of 121.0"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CReal(res_value))) = result { + assert_eq!(res_value, 11.0); } } - - - #[test] fn test_sqrt_zero() { let result = sqrt(vec![EnvValue::Exp(Expression::CReal(0.0))]); - match result { - EnvValue::Exp(Expression::CReal(res_value)) => assert_eq!(res_value, 0.0), - _ => panic!("Incorrect result for sqrt of 0.0"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CReal(res_value))) = result { + assert_eq!(res_value, 0.0); } } #[test] - #[should_panic(expected = "sqrt expects exactly one argument")] fn test_sqrt_invalid_number_of_arguments() { - sqrt(vec![]); + let result = sqrt(vec![]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "sqrt expects exactly one argument"); } #[test] - #[should_panic(expected = "sqrt expects exactly one argument")] fn test_sqrt_invalid_number_of_arguments_multiple() { - sqrt(vec![ + let result = sqrt(vec![ EnvValue::Exp(Expression::CReal(25.0)), EnvValue::Exp(Expression::CReal(9.0)), ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "sqrt expects exactly one argument"); } #[test] - #[should_panic(expected = "sqrt expects a real number argument")] fn test_sqrt_invalid_argument_type() { - sqrt(vec![EnvValue::Exp(Expression::CInt(25))]); + let result = sqrt(vec![EnvValue::Exp(Expression::CInt(25))]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "sqrt expects a real number argument"); } - -//==================================================================================================== +//TESTES FUNCAO FACTORIAL #[test] fn test_factorial_valid_inputs() { let result = factorial(vec![EnvValue::Exp(Expression::CInt(0))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 1), - _ => panic!("Incorrect result for factorial of 0"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 1); } - + let result = factorial(vec![EnvValue::Exp(Expression::CInt(1))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 1), - _ => panic!("Incorrect result for factorial of 1"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 1); } - + let result = factorial(vec![EnvValue::Exp(Expression::CInt(5))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 120), - _ => panic!("Incorrect result for factorial of 5"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 120); } - + let result = factorial(vec![EnvValue::Exp(Expression::CInt(10))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 3628800), - _ => panic!("Incorrect result for factorial of 10"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 3628800); } } #[test] - #[should_panic(expected = "factorial expects exactly one argument")] fn test_factorial_invalid_number_of_arguments() { - factorial(vec![]); + let result = factorial(vec![]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "factorial expects exactly one argument"); } #[test] - #[should_panic(expected = "factorial expects exactly one argument")] fn test_factorial_invalid_number_of_arguments_multiple() { - factorial(vec![EnvValue::Exp(Expression::CInt(1)), EnvValue::Exp(Expression::CInt(2))]); + let result = factorial(vec![ + EnvValue::Exp(Expression::CInt(1)), + EnvValue::Exp(Expression::CInt(2)), + ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "factorial expects exactly one argument"); } #[test] - #[should_panic(expected = "factorial expects a integer argument")] fn test_factorial_invalid_argument_type() { - factorial(vec![EnvValue::Exp(Expression::CReal(3.5))]); + let result = factorial(vec![EnvValue::Exp(Expression::CReal(3.5))]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "factorial expects an integer argument"); } #[test] - #[should_panic(expected = "factorial expects a non-negative integer argument")] fn test_factorial_negative_argument() { - factorial(vec![EnvValue::Exp(Expression::CInt(-1))]); + let result = factorial(vec![EnvValue::Exp(Expression::CInt(-1))]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "factorial expects a non-negative integer argument"); } - -//==================================================================================================== +//TESTES FUNCAO GCD #[test] fn test_gcd_valid_inputs() { - let result = gcd(vec![EnvValue::Exp(Expression::CInt(48)), EnvValue::Exp(Expression::CInt(18))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 6), - _ => panic!("Incorrect result for gcd of 48 and 18"), + let result = gcd(vec![ + EnvValue::Exp(Expression::CInt(48)), + EnvValue::Exp(Expression::CInt(18)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 6); } - let result = gcd(vec![EnvValue::Exp(Expression::CInt(7)), EnvValue::Exp(Expression::CInt(3))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 1), - _ => panic!("Incorrect result for gcd of 7 and 3"), + let result = gcd(vec![ + EnvValue::Exp(Expression::CInt(7)), + EnvValue::Exp(Expression::CInt(3)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 1); } - let result = gcd(vec![EnvValue::Exp(Expression::CInt(-48)), EnvValue::Exp(Expression::CInt(18))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 6), - _ => panic!("Incorrect result for gcd of -48 and 18"), + let result = gcd(vec![ + EnvValue::Exp(Expression::CInt(-48)), + EnvValue::Exp(Expression::CInt(18)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 6); } - let result = gcd(vec![EnvValue::Exp(Expression::CInt(0)), EnvValue::Exp(Expression::CInt(18))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 18), - _ => panic!("Incorrect result for gcd of 0 and 18"), + let result = gcd(vec![ + EnvValue::Exp(Expression::CInt(0)), + EnvValue::Exp(Expression::CInt(18)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 18); } } #[test] - #[should_panic(expected = "gcd expects exactly two arguments")] fn test_gcd_invalid_number_of_arguments() { - gcd(vec![EnvValue::Exp(Expression::CInt(48))]); + let result = gcd(vec![EnvValue::Exp(Expression::CInt(48))]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "gcd expects exactly two arguments"); } #[test] - #[should_panic(expected = "gcd expects exactly two arguments")] fn test_gcd_invalid_number_of_arguments_multiple() { - gcd(vec![ + let result = gcd(vec![ EnvValue::Exp(Expression::CInt(48)), EnvValue::Exp(Expression::CInt(18)), EnvValue::Exp(Expression::CInt(6)), ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "gcd expects exactly two arguments"); } #[test] - #[should_panic(expected = "gcd expects two integer arguments")] fn test_gcd_invalid_argument_type() { - gcd(vec![EnvValue::Exp(Expression::CReal(48.0)), EnvValue::Exp(Expression::CInt(18))]); + let result = gcd(vec![ + EnvValue::Exp(Expression::CReal(48.0)), + EnvValue::Exp(Expression::CInt(18)), + ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "gcd expects two integer arguments"); } - -//==================================================================================================== +//TESTES PARA LCM #[test] fn test_lcm_valid_inputs() { - let result = lcm(vec![EnvValue::Exp(Expression::CInt(48)), EnvValue::Exp(Expression::CInt(18))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 144), - _ => panic!("Incorrect result for lcm of 48 and 18"), + let result = lcm(vec![ + EnvValue::Exp(Expression::CInt(48)), + EnvValue::Exp(Expression::CInt(18)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 144); } - let result = lcm(vec![EnvValue::Exp(Expression::CInt(7)), EnvValue::Exp(Expression::CInt(3))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 21), - _ => panic!("Incorrect result for lcm of 7 and 3"), + let result = lcm(vec![ + EnvValue::Exp(Expression::CInt(7)), + EnvValue::Exp(Expression::CInt(3)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 21); } - let result = lcm(vec![EnvValue::Exp(Expression::CInt(-48)), EnvValue::Exp(Expression::CInt(18))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 144), - _ => panic!("Incorrect result for lcm of -48 and 18"), + let result = lcm(vec![ + EnvValue::Exp(Expression::CInt(-48)), + EnvValue::Exp(Expression::CInt(18)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 144); } - let result = lcm(vec![EnvValue::Exp(Expression::CInt(0)), EnvValue::Exp(Expression::CInt(18))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 0), - _ => panic!("Incorrect result for lcm of 0 and 18"), + let result = lcm(vec![ + EnvValue::Exp(Expression::CInt(0)), + EnvValue::Exp(Expression::CInt(18)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 0); } } #[test] - #[should_panic(expected = "lcm expects exactly two arguments")] fn test_lcm_invalid_number_of_arguments() { - lcm(vec![EnvValue::Exp(Expression::CInt(48))]); + let result = lcm(vec![EnvValue::Exp(Expression::CInt(48))]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "lcm expects exactly two arguments"); } #[test] - #[should_panic(expected = "lcm expects exactly two arguments")] fn test_lcm_invalid_number_of_arguments_multiple() { - lcm(vec![ + let result = lcm(vec![ EnvValue::Exp(Expression::CInt(48)), EnvValue::Exp(Expression::CInt(18)), EnvValue::Exp(Expression::CInt(6)), ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "lcm expects exactly two arguments"); } #[test] - #[should_panic(expected = "lcm expects two integer arguments")] fn test_lcm_invalid_argument_type() { - lcm(vec![EnvValue::Exp(Expression::CReal(48.0)), EnvValue::Exp(Expression::CInt(18))]); - + let result = lcm(vec![ + EnvValue::Exp(Expression::CReal(48.0)), + EnvValue::Exp(Expression::CInt(18)), + ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "lcm expects two integer arguments"); } -//==================================================================================================== +//TESTES PARA COMB #[test] fn test_comb_valid_inputs() { - let result = comb(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(2))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 10), - _ => panic!("Incorrect result for comb(5, 2)"), + let result = comb(vec![ + EnvValue::Exp(Expression::CInt(5)), + EnvValue::Exp(Expression::CInt(2)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 10); } - let result = comb(vec![EnvValue::Exp(Expression::CInt(10)), EnvValue::Exp(Expression::CInt(3))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 120), - _ => panic!("Incorrect result for comb(10, 3)"), + let result = comb(vec![ + EnvValue::Exp(Expression::CInt(10)), + EnvValue::Exp(Expression::CInt(3)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 120); } - let result = comb(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(6))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 0), - _ => panic!("Incorrect result for comb(5, 6)"), + let result = comb(vec![ + EnvValue::Exp(Expression::CInt(5)), + EnvValue::Exp(Expression::CInt(6)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 0); } } #[test] - #[should_panic(expected = "comb expects exactly two arguments")] fn test_comb_invalid_number_of_arguments() { - comb(vec![EnvValue::Exp(Expression::CInt(5))]); + let result = comb(vec![EnvValue::Exp(Expression::CInt(5))]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "comb expects exactly two arguments"); } #[test] - #[should_panic(expected = "comb expects exactly two arguments")] fn test_comb_invalid_number_of_arguments_multiple() { - comb(vec![ + let result = comb(vec![ EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(2)), EnvValue::Exp(Expression::CInt(1)), ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "comb expects exactly two arguments"); } #[test] - #[should_panic(expected = "comb expects two integer arguments")] fn test_comb_invalid_argument_type() { - comb(vec![EnvValue::Exp(Expression::CReal(5.0)), EnvValue::Exp(Expression::CInt(2))]); + let result = comb(vec![ + EnvValue::Exp(Expression::CReal(5.0)), + EnvValue::Exp(Expression::CInt(2)), + ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "comb expects two integer arguments"); } #[test] - #[should_panic(expected = "comb expects non-negative integers")] fn test_comb_negative_arguments() { - comb(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(-2))]); + let result = comb(vec![ + EnvValue::Exp(Expression::CInt(5)), + EnvValue::Exp(Expression::CInt(-2)), + ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "comb expects non-negative integers"); } -//==================================================================================================== +//TESTES PARA PERM #[test] fn test_perm_valid_inputs() { - let result = perm(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(2))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 20), - _ => panic!("Incorrect result for perm(5, 2)"), + let result = perm(vec![ + EnvValue::Exp(Expression::CInt(5)), + EnvValue::Exp(Expression::CInt(2)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 20); } - let result = perm(vec![EnvValue::Exp(Expression::CInt(10)), EnvValue::Exp(Expression::CInt(3))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 720), - _ => panic!("Incorrect result for perm(10, 3)"), + let result = perm(vec![ + EnvValue::Exp(Expression::CInt(10)), + EnvValue::Exp(Expression::CInt(3)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 720); } - let result = perm(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(6))]); - match result { - EnvValue::Exp(Expression::CInt(value)) => assert_eq!(value, 0), - _ => panic!("Incorrect result for perm(5, 6)"), + let result = perm(vec![ + EnvValue::Exp(Expression::CInt(5)), + EnvValue::Exp(Expression::CInt(6)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { + assert_eq!(value, 0); } } #[test] - #[should_panic(expected = "perm expects exactly two arguments")] fn test_perm_invalid_number_of_arguments() { - perm(vec![EnvValue::Exp(Expression::CInt(5))]); + let result = perm(vec![EnvValue::Exp(Expression::CInt(5))]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "perm expects exactly two arguments"); } #[test] - #[should_panic(expected = "perm expects exactly two arguments")] fn test_perm_invalid_number_of_arguments_multiple() { - perm(vec![ + let result = perm(vec![ EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(2)), EnvValue::Exp(Expression::CInt(1)), ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "perm expects exactly two arguments"); } #[test] - #[should_panic(expected = "perm expects two integer arguments")] fn test_perm_invalid_argument_type() { - perm(vec![EnvValue::Exp(Expression::CReal(5.0)), EnvValue::Exp(Expression::CInt(2))]); + let result = perm(vec![ + EnvValue::Exp(Expression::CReal(5.0)), + EnvValue::Exp(Expression::CInt(2)), + ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "perm expects two integer arguments"); } #[test] - #[should_panic(expected = "perm expects non-negative integers")] fn test_perm_negative_arguments() { - perm(vec![EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(-2))]); + let result = perm(vec![ + EnvValue::Exp(Expression::CInt(5)), + EnvValue::Exp(Expression::CInt(-2)), + ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "perm expects non-negative integers"); + } + +//================================================================================================= + #[test] + fn test_is_prime_valid_inputs() { + let result = is_prime(vec![EnvValue::Exp(Expression::CInt(2))]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CTrue)) = result { + assert!(true); + } + + let result = is_prime(vec![EnvValue::Exp(Expression::CInt(3))]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CTrue)) = result { + assert!(true); + } + + let result = is_prime(vec![EnvValue::Exp(Expression::CInt(7))]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CTrue)) = result { + assert!(true); + } + + let result = is_prime(vec![EnvValue::Exp(Expression::CInt(13))]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CTrue)) = result { + assert!(true); + } + + let result = is_prime(vec![EnvValue::Exp(Expression::CInt(17))]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CTrue)) = result { + assert!(true); + } + } + + #[test] + fn test_is_prime_invalid_number_of_arguments() { + let result = is_prime(vec![]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "is_prime expects exactly one argument"); + } + + #[test] + fn test_is_prime_invalid_number_of_arguments_multiple() { + let result = is_prime(vec![ + EnvValue::Exp(Expression::CInt(2)), + EnvValue::Exp(Expression::CInt(3)), + ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "is_prime expects exactly one argument"); + } + + #[test] + fn test_is_prime_invalid_argument_type() { + let result = is_prime(vec![EnvValue::Exp(Expression::CReal(2.0))]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "is_prime expects an integer argument"); + } + + #[test] + fn test_is_prime_negative_argument() { + let result = is_prime(vec![EnvValue::Exp(Expression::CInt(-1))]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "is_prime expects a non-negative integer"); + } + +//================================================================================================= + #[test] + fn test_log_valid_inputs() { + let result = log(vec![ + EnvValue::Exp(Expression::CReal(10.0)), + EnvValue::Exp(Expression::CReal(100.0)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CReal(value))) = result { + assert_eq!(value, 2.0); + } + + let result = log(vec![ + EnvValue::Exp(Expression::CReal(2.0)), + EnvValue::Exp(Expression::CReal(8.0)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CReal(value))) = result { + assert_eq!(value, 3.0); + } + + let result = log(vec![ + EnvValue::Exp(Expression::CReal(10.0)), + EnvValue::Exp(Expression::CReal(10000.0)), + ]); + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CReal(value))) = result { + assert_eq!(value, 4.0); + } + } + + #[test] + fn test_log_invalid_number_of_arguments() { + let result = log(vec![EnvValue::Exp(Expression::CReal(10.0))]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "log expects exactly two arguments"); + } + + #[test] + fn test_log_invalid_number_of_arguments_multiple() { + let result = log(vec![ + EnvValue::Exp(Expression::CReal(10.0)), + EnvValue::Exp(Expression::CReal(100.0)), + EnvValue::Exp(Expression::CReal(10.0)), + ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "log expects exactly two arguments"); + } + + #[test] + fn test_log_invalid_argument_type() { + let result = log(vec![ + EnvValue::Exp(Expression::CInt(10)), + EnvValue::Exp(Expression::CReal(100.0)), + ]); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "log expects two real arguments"); } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index d735b12..964a7da 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -1,6 +1,4 @@ use crate::ir::ast::{EnvValue, Expression}; -use crate::ir::ast::Environment; -use std::collections::HashMap; pub fn str_upper(args: Vec) -> EnvValue { if args.len() != 1 { diff --git a/src/tc/type_checker.rs b/src/tc/type_checker.rs index ce0f01f..c85d783 100644 --- a/src/tc/type_checker.rs +++ b/src/tc/type_checker.rs @@ -28,12 +28,7 @@ pub fn check_exp(exp: Expression, env: &Environment) -> Result check_bin_relational_expression(*l, *r, env), Expression::Var(name) => check_var_name(name, env), Expression::FuncCall(name, args) => check_func_call(name, args, env), - Expression::MetaExp(_, args, return_type) => { - for arg in args { - check_exp(arg.clone(), env)?; - } - Ok(return_type) - } + Expression::MetaExp(_, args, return_type) => check_metastmt(args, return_type, env), } } @@ -167,10 +162,7 @@ pub fn check_stmt( } let mut new_env = env.clone(); - new_env.insert( - "metaResult".to_string(), - (Some(EnvValue::Exp(Expression::Var("result".to_string()))), return_type.clone()) - ); + new_env.insert("metaResult".to_string(), (None, return_type.clone())); Ok(ControlType::Continue(new_env)) } @@ -278,6 +270,17 @@ fn check_bin_relational_expression( } } +fn check_metastmt( + args: Vec, + return_type: Type, + env: &Environment, +) -> Result { + for arg in args { + check_exp(arg.clone(), env)?; + } + Ok(return_type) +} + #[cfg(test)] mod tests { use std::collections::HashMap; From 5c71468615d2d37caabf3a08150f8e5d2802ee72 Mon Sep 17 00:00:00 2001 From: Marquito-2003 Date: Sun, 16 Feb 2025 13:06:44 -0300 Subject: [PATCH 10/15] =?UTF-8?q?Fun=C3=A7=C3=B5es=20de=20strings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/interpreter/interpreter.rs | 327 ++++++++++++++++++++++++++++++++- src/stdlib/string.rs | 325 +++++--------------------------- 2 files changed, 376 insertions(+), 276 deletions(-) diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index cbbfc57..905ded2 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -498,7 +498,7 @@ mod tests { use crate::ir::ast::Statement::*; use crate::ir::ast::Type::*; use crate::stdlib::math::{sqrt, gcd}; - //use crate::stdlib::string::{str_upper}; + use crate::stdlib::string::{str_upper, str_lower, str_length, str_reverse, cont_chars, filter_out_char, replace}; use approx::relative_eq; @@ -1456,5 +1456,328 @@ mod tests { } } - */ + */ + #[test] + fn metastmt_function_upper() { + /* + * Teste para a função de conversão de string para maiúsculas usando MetaStmt + * + * Código imaginário em rpy: + * + * > x: TString = "hello" + * > def upper(x: TString) -> TString: + * > MetaStmt(str_upper, [x], TString) + * > return metaResult + * > result = upper(x) + * + * Após a execução, 'result' deve ser "HELLO". + */ + let env = HashMap::new(); + let program = Statement::Sequence( + Box::new(Statement::Assignment( + "x".to_string(), + Box::new(Expression::CString("hello".to_string())), + Some(Type::TString), + )), + Box::new(Statement::MetaStmt( + str_upper, + vec![Expression::Var("x".to_string())], + Type::TString, + )), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some((Some(EnvValue::Exp(Expression::CString(result))), _)) = new_env.get("metaResult") { + assert_eq!(result, "HELLO"); + } else { + panic!("metaResult not found or invalid type"); + } + } + _ => panic!("Test failed"), + } + } + + #[test] + fn metastmt_function_lower() { + /* + * Teste para a função de conversão de string para minúsculas usando MetaStmt + * + * Código imaginário em rpy: + * + * > x: TString = "HELLO" + * > def lower(x: TString) -> TString: + * > MetaStmt(str_lower, [x], TString) + * > return metaResult + * > result = lower(x) + * + * Após a execução, 'result' deve ser "hello". + */ + let env = HashMap::new(); + let program = Statement::Sequence( + Box::new(Statement::Assignment( + "x".to_string(), + Box::new(Expression::CString("HELLO".to_string())), + Some(Type::TString), + )), + Box::new(Statement::MetaStmt( + str_lower, + vec![Expression::Var("x".to_string())], + Type::TString, + )), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some((Some(EnvValue::Exp(Expression::CString(result))), _)) = new_env.get("metaResult") { + assert_eq!(result, "hello"); + } else { + panic!("metaResult not found or invalid type"); + } + } + _ => panic!("Test failed"), + } + } + + #[test] + fn metastmt_function_length() { + /* + * Teste para a função de obtenção do comprimento de uma string usando MetaStmt + * + * Código imaginário em rpy: + * + * > x: TString = "hello" + * > def length(x: TString) -> TInteger: + * > MetaStmt(str_length, [x], TInteger) + * > return metaResult + * > result = length(x) + * + * Após a execução, 'result' deve ser 5. + */ + let env = HashMap::new(); + let program = Statement::Sequence( + Box::new(Statement::Assignment( + "x".to_string(), + Box::new(Expression::CString("hello".to_string())), + Some(Type::TString), + )), + Box::new(Statement::MetaStmt( + str_length, + vec![Expression::Var("x".to_string())], + Type::TInteger, + )), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some((Some(EnvValue::Exp(Expression::CInt(result))), _)) = new_env.get("metaResult") { + assert_eq!(*result, 5); + } else { + panic!("metaResult not found or invalid type"); + } + } + _ => panic!("Test failed"), + } + } + + #[test] + fn metastmt_function_reverse() { + /* + * Teste para a função de reversão de string usando MetaStmt + * + * Código imaginário em rpy: + * + * > x: TString = "hello" + * > def reverse(x: TString) -> TString: + * > MetaStmt(str_reverse, [x], TString) + * > return metaResult + * > result = reverse(x) + * + * Após a execução, 'result' deve ser "olleh". + */ + let env = HashMap::new(); + let program = Statement::Sequence( + Box::new(Statement::Assignment( + "x".to_string(), + Box::new(Expression::CString("hello".to_string())), + Some(Type::TString), + )), + Box::new(Statement::MetaStmt( + str_reverse, + vec![Expression::Var("x".to_string())], + Type::TString, + )), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some((Some(EnvValue::Exp(Expression::CString(result))), _)) = new_env.get("metaResult") { + assert_eq!(result, "olleh"); + } else { + panic!("metaResult not found or invalid type"); + } + } + _ => panic!("Test failed"), + } + } + + #[test] + fn metastmt_function_cont_chars() { + /* + * Teste para a função de contagem de caracteres usando MetaStmt + * + * Código imaginário em rpy: + * + * > s: TString = "banana" + * > c: TString = "a" + * > def cont_chars(s: TString, c: TString) -> TInteger: + * > MetaStmt(cont_chars, [s, c], TInteger) + * > return metaResult + * > result = cont_chars(s, c) + * + * Após a execução, 'result' deve ser 3. + */ + let env = HashMap::new(); + let program = Statement::Sequence( + Box::new(Statement::Assignment( + "s".to_string(), + Box::new(Expression::CString("banana".to_string())), + Some(Type::TString), + )), + Box::new(Statement::Sequence( + Box::new(Statement::Assignment( + "c".to_string(), + Box::new(Expression::CString("a".to_string())), + Some(Type::TString), + )), + Box::new(Statement::MetaStmt( + cont_chars, + vec![Expression::Var("s".to_string()), Expression::Var("c".to_string())], + Type::TInteger, + )), + )), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some((Some(EnvValue::Exp(Expression::CInt(result))), _)) = new_env.get("metaResult") { + assert_eq!(*result, 3); + } else { + panic!("metaResult not found or invalid type"); + } + } + _ => panic!("Test failed"), + } + } + + #[test] + fn metastmt_function_filter_out_char() { + /* + * Teste para a função de remoção de um caractere específico de uma string usando MetaStmt + * + * Código imaginário em rpy: + * + * > s: TString = "banana" + * > c: TString = "a" + * > def filter_out_char(s: TString, c: TString) -> TString: + * > MetaStmt(filter_out_char, [s, c], TString) + * > return metaResult + * > result = filter_out_char(s, c) + * + * Após a execução, 'result' deve ser "bnn". + */ + let env = HashMap::new(); + let program = Statement::Sequence( + Box::new(Statement::Assignment( + "s".to_string(), + Box::new(Expression::CString("banana".to_string())), + Some(Type::TString), + )), + Box::new(Statement::Sequence( + Box::new(Statement::Assignment( + "c".to_string(), + Box::new(Expression::CString("a".to_string())), + Some(Type::TString), + )), + Box::new(Statement::MetaStmt( + filter_out_char, + vec![Expression::Var("s".to_string()), Expression::Var("c".to_string())], + Type::TString, + )), + )), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some((Some(EnvValue::Exp(Expression::CString(result))), _)) = new_env.get("metaResult") { + assert_eq!(result, "bnn"); + } else { + panic!("metaResult not found or invalid type"); + } + } + _ => panic!("Test failed"), + } + } + + #[test] + fn metastmt_function_replace() { + /* + * Teste para a função de substituição de caracteres em uma string usando MetaStmt + * + * Código imaginário em rpy: + * + * > s: TString = "banana" + * > old: TString = "a" + * > new: TString = "o" + * > def replace(s: TString, old: TString, new: TString) -> TString: + * > MetaStmt(replace, [s, old, new], TString) + * > return metaResult + * > result = replace(s, old, new) + * + * Após a execução, 'result' deve ser "bonono". + */ + let env = HashMap::new(); + let program = Statement::Sequence( + Box::new(Statement::Assignment( + "s".to_string(), + Box::new(Expression::CString("banana".to_string())), + Some(Type::TString), + )), + Box::new(Statement::Sequence( + Box::new(Statement::Assignment( + "old".to_string(), + Box::new(Expression::CString("a".to_string())), + Some(Type::TString), + )), + Box::new(Statement::Sequence( + Box::new(Statement::Assignment( + "new".to_string(), + Box::new(Expression::CString("o".to_string())), + Some(Type::TString), + )), + Box::new(Statement::MetaStmt( + replace, + vec![ + Expression::Var("s".to_string()), + Expression::Var("old".to_string()), + Expression::Var("new".to_string()), + ], + Type::TString, + )), + )), + )), + ); + + match execute(program, &env, true) { + Ok(ControlFlow::Continue(new_env)) => { + if let Some((Some(EnvValue::Exp(Expression::CString(result))), _)) = new_env.get("metaResult") { + assert_eq!(result, "bonono"); + } else { + panic!("metaResult not found or invalid type"); + } + } + _ => panic!("Test failed"), + } + } + } diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 964a7da..def0ec8 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -1,93 +1,90 @@ use crate::ir::ast::{EnvValue, Expression}; -pub fn str_upper(args: Vec) -> EnvValue { +pub fn str_upper(args: Vec) -> Result { if args.len() != 1 { - panic!("str_upper expects exactly one argument"); + return Err("str_upper expects exactly one argument".to_string()); } if let EnvValue::Exp(Expression::CString(s)) = &args[0] { - EnvValue::Exp(Expression::CString(s.to_uppercase())) + Ok(EnvValue::Exp(Expression::CString(s.to_uppercase()))) } else { - panic!("str_upper expects a string argument"); + Err("str_upper expects a string argument".to_string()) } -} +} -pub fn str_lower(args: Vec) -> EnvValue { +pub fn str_lower(args: Vec) -> Result { if args.len() != 1 { - panic!("str_lower expects exactly one argument"); + return Err("str_lower expects exactly one argument".to_string()); } if let EnvValue::Exp(Expression::CString(s)) = &args[0] { - EnvValue::Exp(Expression::CString(s.to_lowercase())) + Ok(EnvValue::Exp(Expression::CString(s.to_lowercase()))) } else { - panic!("str_lower expects a string argument"); + Err("str_lower expects a string argument".to_string()) } } -pub fn str_length(args: Vec) -> EnvValue { +pub fn str_length(args: Vec) -> Result { if args.len() != 1 { - panic!("str_length expects exactly one argument"); + return Err("str_length expects exactly one argument".to_string()); } if let EnvValue::Exp(Expression::CString(s)) = &args[0] { - EnvValue::Exp(Expression::CInt(s.chars().count() as i32)) + Ok(EnvValue::Exp(Expression::CInt(s.chars().count() as i32))) } else { - panic!("str_length expects a string argument"); + Err("str_length expects a string argument".to_string()) } } -pub fn str_reverse(args: Vec) -> EnvValue { +pub fn str_reverse(args: Vec) -> Result { if args.len() != 1 { - panic!("str_reverse expects exactly one argument"); + return Err("str_reverse expects exactly one argument".to_string()); } if let EnvValue::Exp(Expression::CString(s)) = &args[0] { - EnvValue::Exp(Expression::CString(s.chars().rev().collect())) + Ok(EnvValue::Exp(Expression::CString(s.chars().rev().collect()))) } else { - panic!("str_reverse expects a string argument"); + Err("str_reverse expects a string argument".to_string()) } } -//conta quantas vezes aparece um char especifico -pub fn cont_chars(args: Vec) -> EnvValue { +pub fn cont_chars(args: Vec) -> Result { if args.len() != 2 { - panic!("cont_chars expects exactly two arguments"); + return Err("cont_chars expects exactly two arguments".to_string()); } if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = (&args[0], &args[1]) { if c.len() != 1 { - panic!("cont_chars expects a single character as the second argument"); + return Err("cont_chars expects a single character as the second argument".to_string()); } let target = c.chars().next().unwrap(); - EnvValue::Exp(Expression::CInt(s.chars().filter(|&ch| ch == target).count() as i32)) + Ok(EnvValue::Exp(Expression::CInt(s.chars().filter(|&ch| ch == target).count() as i32))) } else { - panic!("cont_chars expects a string and a character as arguments"); + Err("cont_chars expects a string and a character as arguments".to_string()) } } -//retira todas as aparicoes de um char especifico -pub fn filter_out_char(args: Vec) -> EnvValue { +pub fn filter_out_char(args: Vec) -> Result { if args.len() != 2 { - panic!("filter_out_char expects exactly two arguments"); + return Err("filter_out_char expects exactly two arguments".to_string()); } if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = (&args[0], &args[1]) { if c.len() != 1 { - panic!("filter_out_char expects a single character as the second argument"); + return Err("filter_out_char expects a single character as the second argument".to_string()); } let target = c.chars().next().unwrap(); - EnvValue::Exp(Expression::CString(s.chars().filter(|&ch| ch != target).collect())) + Ok(EnvValue::Exp(Expression::CString(s.chars().filter(|&ch| ch != target).collect()))) } else { - panic!("filter_out_char expects a string and a character as arguments"); + Err("filter_out_char expects a string and a character as arguments".to_string()) } } -// substitui os N primeiros caracteres "old" por um novo caracter "new" -pub fn replace(args: Vec) -> EnvValue { +pub fn replace(args: Vec) -> Result { if args.len() < 3 || args.len() > 4 { - panic!("replace expects between 3 and 4 arguments"); + return Err("replace expects between 3 and 4 arguments".to_string()); } if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(old)), EnvValue::Exp(Expression::CString(new))) = (&args[0], &args[1], &args[2]) { let count = if args.len() == 4 { if let EnvValue::Exp(Expression::CInt(n)) = &args[3] { *n } else { - panic!("replace expects an integer as the fourth argument (count)"); + return Err("replace expects an integer as the fourth argument (count)".to_string()); } } else { -1 @@ -109,187 +106,42 @@ pub fn replace(args: Vec) -> EnvValue { result }; - EnvValue::Exp(Expression::CString(result)) - } else { - panic!("replace expects three string arguments and an optional integer"); - } -} - -//centraliza a string e preenche o resto com um char -pub fn center(args: Vec) -> EnvValue { - if args.len() != 3 { - panic!("center expects exactly three arguments"); - } - - if let ( - EnvValue::Exp(Expression::CString(s)), - EnvValue::Exp(Expression::CInt(width)), - EnvValue::Exp(Expression::CString(fillchar)), - ) = (&args[0], &args[1], &args[2]) - { - if fillchar.len() != 1 { - panic!("center expects a single character as the fill character"); - } - - let fill = fillchar.chars().next().unwrap(); - let pad = (*width as usize).saturating_sub(s.len()); - let left = pad / 2; - let right = pad - left; - - let centered = format!( - "{}{}{}", - fill.to_string().repeat(left), - s, - fill.to_string().repeat(right) - ); - - EnvValue::Exp(Expression::FuncCall( - "center".to_string(), - vec![Expression::CString(centered)], - )) - } else { - panic!("center expects a string, an integer width, and a character as arguments"); - } -} - -//acha uma substring -pub fn find(args: Vec) -> EnvValue { - if args.len() < 2 || args.len() > 4 { - panic!("find expects between 2 and 4 arguments"); - } - - if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(sub))) = - (&args[0], &args[1]) - { - let start = if args.len() > 2 { - if let EnvValue::Exp(Expression::CInt(n)) = &args[2] { - *n as usize - } else { - panic!("find expects an integer as the third argument (start index)"); - } - } else { - 0 - }; - - let end = if args.len() > 3 { - if let EnvValue::Exp(Expression::CInt(n)) = &args[3] { - Some(*n as usize) - } else { - panic!("find expects an integer as the fourth argument (end index)"); - } - } else { - None - }; - - let end = end.unwrap_or(s.len()); - let result = match s.get(start..end) { - Some(substring) => substring.find(sub).map(|i| i + start), - None => None, - }; - - let retorno = match result { - Some(index) => EnvValue::Exp(Expression::CInt(index as i32)), - None => EnvValue::Exp(Expression::CInt(-1)), - }; - - if let EnvValue::Exp(expr) = retorno { - EnvValue::Exp(Expression::FuncCall("find".to_string(), vec![expr])) - } else { - panic!("invalid return value type"); - } - + Ok(EnvValue::Exp(Expression::CString(result))) } else { - panic!("find expects two strings as first arguments"); + Err("replace expects three string arguments and an optional integer".to_string()) } } -//recebe uma lista de strings e junta elas em uma string so -pub fn join(args: Vec) -> EnvValue { - if args.len() != 2 { - panic!("join expects exactly two arguments"); - } - if let ( - EnvValue::Exp(Expression::CString(sep)), - EnvValue::Exp(Expression::FuncCall(_, lista)), - ) = (&args[0], &args[1]) - { - let strings: Vec = lista - .iter() - .map(|expr| { - if let Expression::CString(s) = expr { - s.clone() - } else { - panic!("join expects a list of strings as the second argument"); - } - }) - .collect(); - EnvValue::Exp(Expression::CString(strings.join(sep))) - } else { - panic!("join expects a string and a list of strings as arguments"); - } -} - -pub fn partition(args: Vec) -> EnvValue { - if args.len() != 2 { - panic!("partition expects exactly two arguments"); - } - - if let ( - EnvValue::Exp(Expression::CString(s)), - EnvValue::Exp(Expression::CString(sep)), - ) = (&args[0], &args[1]) - { - match s.find(sep) { - Some(index) => EnvValue::Exp(Expression::FuncCall( - "tuple".to_string(), - vec![ - Expression::CString(s[..index].to_string()), - Expression::CString(sep.clone()), - Expression::CString(s[index + sep.len()..].to_string()), - ], - )), - None => EnvValue::Exp(Expression::FuncCall( - "tuple".to_string(), - vec![ - Expression::CString(s.to_string()), - Expression::CString(String::new()), - Expression::CString(String::new()), - ], - )), - } - } else { - panic!("partition expects two string arguments"); - } -} #[cfg(test)] mod tests { use super::*; + #[test] fn test_str_lower_valid_strings() { let result = str_lower(vec![EnvValue::Exp(Expression::CString(String::from("HELLO")))]); - match result { - EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "hello"), - _ => panic!("Incorrect result for str_lower('HELLO')"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CString(res_value))) = result { + assert_eq!(res_value, "hello"); } } #[test] fn test_str_length_valid_string() { let result = str_length(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); - match result { - EnvValue::Exp(Expression::CInt(len)) => assert_eq!(len, 5), - _ => panic!("Incorrect result for str_length('hello')"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(len))) = result { + assert_eq!(len, 5); } } #[test] fn test_str_reverse_valid_string() { let result = str_reverse(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); - match result { - EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "olleh"), - _ => panic!("Incorrect result for str_reverse('hello')"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CString(res_value))) = result { + assert_eq!(res_value, "olleh"); } } @@ -299,9 +151,9 @@ mod tests { EnvValue::Exp(Expression::CString(String::from("banana"))), EnvValue::Exp(Expression::CString(String::from("a"))), ]); - match result { - EnvValue::Exp(Expression::CInt(count)) => assert_eq!(count, 3), - _ => panic!("Incorrect result for cont_chars('banana', 'a')"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CInt(count))) = result { + assert_eq!(count, 3); } } @@ -311,9 +163,9 @@ mod tests { EnvValue::Exp(Expression::CString(String::from("banana"))), EnvValue::Exp(Expression::CString(String::from("a"))), ]); - match result { - EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "bnn"), - _ => panic!("Incorrect result for filter_out_char('banana', 'a')"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CString(res_value))) = result { + assert_eq!(res_value, "bnn"); } } @@ -324,85 +176,10 @@ mod tests { EnvValue::Exp(Expression::CString(String::from("a"))), EnvValue::Exp(Expression::CString(String::from("o"))), ]); - match result { - EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "bonono"), - _ => panic!("Incorrect result for replace('banana', 'a', 'o')"), + assert!(result.is_ok()); + if let Ok(EnvValue::Exp(Expression::CString(res_value))) = result { + assert_eq!(res_value, "bonono"); } } - #[test] - fn test_center_valid_input() { - let result = center(vec![ - EnvValue::Exp(Expression::CString(String::from("hello"))), - EnvValue::Exp(Expression::CInt(11)), - EnvValue::Exp(Expression::CString(String::from("*"))), - ]); - match result { - EnvValue::Exp(Expression::FuncCall(_, args)) => { - if let Expression::CString(centered) = &args[0] { - assert_eq!(centered, "***hello***"); - } else { - panic!("Incorrect result for center('hello', 11, '*')"); - } - } - _ => panic!("Incorrect return type for center"), - } - } - - #[test] - fn test_find_valid_input() { - let result = find(vec![ - EnvValue::Exp(Expression::CString(String::from("hello world"))), - EnvValue::Exp(Expression::CString(String::from("world"))), - ]); - match result { - EnvValue::Exp(Expression::FuncCall(_, args)) => { - if let Expression::CInt(index) = &args[0] { - assert_eq!(*index, 6); - } else { - panic!("Incorrect result for find('hello world', 'world')"); - } - } - _ => panic!("Incorrect return type for find"), - } - } - - #[test] - fn test_join_valid_input() { - let result = join(vec![ - EnvValue::Exp(Expression::CString(String::from(","))), - EnvValue::Exp(Expression::FuncCall( - "list".to_string(), - vec![ - Expression::CString(String::from("a")), - Expression::CString(String::from("b")), - Expression::CString(String::from("c")), - ], - )), - ]); - match result { - EnvValue::Exp(Expression::CString(res_value)) => assert_eq!(res_value, "a,b,c"), - _ => panic!("Incorrect result for join(',', ['a', 'b', 'c'])"), - } - } - - #[test] - fn test_partition_valid_input() { - let result = partition(vec![ - EnvValue::Exp(Expression::CString(String::from("banana"))), - EnvValue::Exp(Expression::CString(String::from("n"))), - ]); - match result { - EnvValue::Exp(Expression::FuncCall(_, args)) => { - if let (Expression::CString(left), Expression::CString(sep), Expression::CString(right)) = (&args[0], &args[1], &args[2]) { - assert_eq!(left, "ba"); - assert_eq!(sep, "n"); - assert_eq!(right, "ana"); - } else { - panic!("Incorrect result for partition('banana', 'n')"); - } - } - _ => panic!("Incorrect return type for partition"), - } - } } \ No newline at end of file From f938442f846d9f7acdf4782cb7330a20756f6d8c Mon Sep 17 00:00:00 2001 From: Layr Neto Date: Mon, 17 Feb 2025 08:19:02 -0300 Subject: [PATCH 11/15] parsing do meta --- src/parser/parser.rs | 120 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 8e46ce0..e15c866 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -14,6 +14,9 @@ type ParseResult<'a, T> = IResult<&'a str, T, Error<&'a str>>; use crate::ir::ast::Function; use crate::ir::ast::Type; use crate::ir::ast::{Expression, Name, Statement}; +use crate::stdlib::math::*; +use crate::stdlib::string::*; +use crate::ir::ast::EnvValue; // Parse identifier fn identifier(input: &str) -> IResult<&str, Name> { @@ -69,6 +72,7 @@ fn term(input: &str) -> ParseResult { fn statement(input: &str) -> IResult<&str, Statement> { let (input, _) = space0(input)?; alt(( + meta_stmt, function_def, if_statement, return_statement, @@ -80,6 +84,7 @@ fn statement(input: &str) -> IResult<&str, Statement> { // Parse basic expressions fn expression(input: &str) -> IResult<&str, Expression> { alt(( + meta_exp, boolean_expression, comparison_expression, arithmetic_expression, @@ -370,6 +375,76 @@ fn return_statement(input: &str) -> IResult<&str, Statement> { Ok((input, Statement::Return(Box::new(expr)))) } +//meta parsing +fn meta_exp(input: &str) -> IResult<&str, Expression> { + let (input, _) = tag("MetaExp")(input)?; + let (input, _) = space0(input)?; + let (input, _) = char('(')(input)?; + let (input, meta_func_id) = identifier(input)?; + let (input, _) = delimited(space0, char(','), space0)(input)?; + let (input, args) = delimited( + char('['), + separated_list0(delimited(space0, char(','), space0), expression), + char(']') + )(input)?; + let (input, _) = delimited(space0, char(','), space0)(input)?; + let (input, type_str) = identifier(input)?; + let (input, _) = char(')')(input)?; + + let meta_func = match resolve_meta_function(&meta_func_id) { + Ok(func) => func, + Err(_) => return Err(nom::Err::Failure(Error::new(input, ErrorKind::Tag))), + }; + let meta_type = parse_type(&type_str); + + Ok((input, Expression::MetaExp(meta_func, args, meta_type))) +} + +fn meta_stmt(input: &str) -> IResult<&str, Statement> { + let (input, _) = tag("MetaStmt")(input)?; + let (input, _) = space0(input)?; + let (input, _) = char('(')(input)?; + let (input, meta_func_id) = identifier(input)?; + let (input, _) = delimited(space0, char(','), space0)(input)?; + let (input, args) = delimited( + char('['), + separated_list0(delimited(space0, char(','), space0), expression), + char(']') + )(input)?; + let (input, _) = delimited(space0, char(','), space0)(input)?; + let (input, type_str) = identifier(input)?; + let (input, _) = char(')')(input)?; + + let meta_func = match resolve_meta_function(&meta_func_id) { + Ok(func) => func, + Err(_) => return Err(nom::Err::Failure(Error::new(input, ErrorKind::Tag))), + }; + let meta_type = parse_type(&type_str); + + Ok((input, Statement::MetaStmt(meta_func, args, meta_type))) +} + +fn resolve_meta_function(id: &str) -> Result) -> Result, String> { + match id { + "sqrt" => Ok(sqrt), + "factorial" => Ok(factorial), + "gcd" => Ok(gcd), + "lcm" => Ok(lcm), + "comb" => Ok(comb), + "perm" => Ok(perm), + "is_prime" => Ok(is_prime), + "log" => Ok(log), + "str_upper" => Ok(str_upper), + "str_lower" => Ok(str_lower), + "str_length" => Ok(str_length), + "str_reverse" => Ok(str_reverse), + "cont_chars" => Ok(cont_chars), + "filter_out_char" => Ok(filter_out_char), + "replace" => Ok(replace), + _ => Err(format!("Meta function '{}' não encontrada", id)), + } +} + // Parse multiple statements pub fn parse_statements(input: &str) -> IResult<&str, Vec> { let (input, _) = space0(input)?; // Handle initial whitespace @@ -884,4 +959,49 @@ mod tests { assert_eq!(rest, ""); assert_eq!(result, expected); } + + #[test] + fn test_metaexp_parsing() { + let input = "x = MetaExp(sqrt, [x], TReal)"; + let (rest, stmts) = parse(input).unwrap(); + assert_eq!(rest, ""); + + match &stmts[0] { + Statement::Assignment(name, expr, _type) => { + assert_eq!(name, "x"); + match &**expr { + Expression::MetaExp(_, args, meta_type) => { + assert_eq!(meta_type, &Type::TReal); + assert_eq!(args.len(), 1); + match &args[0] { + Expression::Var(var_name) => assert_eq!(var_name, "x"), + _ => panic!("Expected a variable as argument in MetaExp"), + } + }, + _ => panic!("Expected a MetaExp expression"), + } + }, + _ => panic!("Expected an Assignment statement"), + } + } + + #[test] + fn test_metastmt_parsing() { + let input = "MetaStmt(sqrt, [x], TReal)"; + let (rest, stmt) = meta_stmt(input).unwrap(); + assert_eq!(rest, ""); + + match stmt { + Statement::MetaStmt(_, args, meta_type) => { + assert_eq!(meta_type, Type::TReal); + assert_eq!(args.len(), 1); + match &args[0] { + Expression::Var(var_name) => assert_eq!(var_name, "x"), + _ => panic!("Expected a variable as argument in MetaStmt"), + } + }, + _ => panic!("Expected a MetaStmt statement"), + } + } + } From bc3731e8d4c0e322d001b6fc6baea672d00a104a Mon Sep 17 00:00:00 2001 From: Layr Date: Wed, 19 Feb 2025 20:27:54 -0300 Subject: [PATCH 12/15] hashmap com a stdlib e abordagem totalmente interna para o Meta --- src/interpreter/interpreter.rs | 751 +-------------------------------- src/ir/ast.rs | 1 - src/parser/parser.rs | 120 ------ src/stdlib.rs | 3 +- src/stdlib/math.rs | 217 +++++++--- src/stdlib/stdlib.rs | 438 +++++++++++++++++++ src/stdlib/string.rs | 148 ++++++- src/tc/type_checker.rs | 103 +---- 8 files changed, 741 insertions(+), 1040 deletions(-) create mode 100644 src/stdlib/stdlib.rs diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 905ded2..f2d0044 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -124,31 +124,6 @@ pub fn execute( Ok(ControlFlow::Return(value)) } - Statement::MetaStmt(f, args_exprs, return_type) => { - let mut args_values = Vec::new(); - for expr in &args_exprs { - let env_value = eval(expr.clone(), &new_env)?; - args_values.push(env_value); - } - - let result_value = f(args_values)?; - - if get_type_env_value(&result_value) != return_type { - return Err(format!( - "Mismatched types: expected {:?}, but the function returned {:?}", - return_type, - get_type_env_value(&result_value) - )); - } - - new_env.insert( - "metaResult".to_string(), - (Some(result_value.clone()), return_type.clone()), - ); - - Ok(ControlFlow::Continue(new_env)) - } - _ => Err(String::from("not implemented yet")), } } @@ -497,8 +472,7 @@ mod tests { use crate::ir::ast::Function; use crate::ir::ast::Statement::*; use crate::ir::ast::Type::*; - use crate::stdlib::math::{sqrt, gcd}; - use crate::stdlib::string::{str_upper, str_lower, str_length, str_reverse, cont_chars, filter_out_char, replace}; + use crate::stdlib::math::sqrt_impl; use approx::relative_eq; @@ -1057,727 +1031,24 @@ mod tests { } } - #[test] - fn metastmt_sqrt() { - /* - * Test for the square root function (sqrt) using MetaStmt - * - * Imaginary rpy code: - * - * > x: TReal = 16.0 - * > MetaStmt(sqrt, [x], TReal) - * > result: TReal = metaResult - * - * After execution, 'result' should be 4.0 (sqrt(16.0) = 4.0). - */ - - let env = Environment::new(); - - let assign_x = Statement::Assignment( + fn test_metaexp_sqrt() { + let mut env = HashMap::new(); + env.insert( "x".to_string(), - Box::new(Expression::CReal(16.0)), - Some(TReal), - ); - - let meta_stmt = Statement::MetaStmt( - sqrt, - vec![Expression::Var("x".to_string())], - TReal + (Some(EnvValue::Exp(Expression::CReal(25.0))), Type::TReal) ); - let assign_result = Statement::Assignment( - "result".to_string(), - Box::new(Expression::Var("metaResult".to_string())), - Some(TReal), - ); - - let program = Statement::Sequence( - Box::new(assign_x), - Box::new(Statement::Sequence( - Box::new(meta_stmt), - Box::new(assign_result), - )), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some(&(Some(EnvValue::Exp(Expression::CReal(value))), _)) = new_env.get("metaResult") { - assert_eq!(value, 4.0); - } else { - panic!("Variable 'metaResult' not found or has incorrect type"); - } - } - Ok(_) => panic!("The interpreter did not continue execution as expected"), - Err(err) => panic!("Interpreter execution failed with error: {}", err), - } - } - - #[test] - fn metastmt_function_sqrt() { - /* - * Test for the r-python square root function (sqrt) using MetaStmt - * - * Imaginary rpy code: - * - * > x: TReal = 25.0 - * > def sqrt(x: TReal) -> TReal: - * > MetaStmt(sqrt, [x], TReal) - * > return metaResult - * > x = sqrt(x) - * - * After execution, 'x' should be 5.0 (sqrt(25.0) = 5.0). - */ - let env = Environment::new(); - - let assign_x = Statement::Assignment( - "x".to_string(), - Box::new(Expression::CReal(25.0)), - Some(TReal), - ); - - let meta_stmt = Statement::MetaStmt( - sqrt, - vec![Expression::Var("x".to_string())], - TReal - ); - - let func: Statement = FuncDef( - "sqrt".to_string(), - Function { - kind: TReal, - params: Some(vec![("x".to_string(), TReal)]), - body: Box::new(Sequence( - Box::new(meta_stmt), - Box::new(Return( - Box::new(Expression::Var("metaResult".to_string())) - )) - )) - } - ); - - let assign_result = Statement::Assignment( - "x".to_string(), - Box::new(Expression::FuncCall("sqrt".to_string(), vec![Expression::Var("x".to_string())])), - Some(TReal), - ); - - let program = Statement::Sequence( - Box::new(assign_x), - Box::new(Statement::Sequence( - Box::new(func), - Box::new(assign_result), - )), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some(&(Some(EnvValue::Exp(Expression::CReal(value))), _)) = new_env.get("x") { - assert_eq!(value, 5.0); - } else { - panic!("Variable 'x' not found or has incorrect type"); - } - } - Ok(_) => panic!("The interpreter did not continue execution as expected"), - Err(err) => panic!("Interpreter execution failed with error: {}", err), - } - } - - #[test] - fn metastmt_function_gcd() { - /* - * Test for the greatest common divisor function (gcd) using MetaStmt - * - * Imaginary rpy code: - * - * > a: TInteger = 48 - * > b: TInteger = 18 - * > def gcd(a: TInteger, b: TInteger) -> TInteger: - * > MetaStmt(gcd, [a, b], TInteger) - * > return metaResult - * > result = gcd(a, b) - * - * After execution, 'result' should be 6 (gcd(48, 18) = 6). - */ - - let env = Environment::new(); - - let assign_a = Statement::Assignment( - "a".to_string(), - Box::new(Expression::CInt(48)), - Some(TInteger), - ); - - let assign_b = Statement::Assignment( - "b".to_string(), - Box::new(Expression::CInt(18)), - Some(TInteger), - ); - - let meta_stmt = Statement::MetaStmt( - gcd, - vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], - TInteger, - ); - - let func: Statement = Statement::FuncDef( - "gcd".to_string(), - Function { - kind: TInteger, - params: Some(vec![("a".to_string(), TInteger), ("b".to_string(), TInteger)]), - body: Box::new(Statement::Sequence( - Box::new(meta_stmt), - Box::new(Statement::Return( - Box::new(Expression::Var("metaResult".to_string())) - )), - )), - }, - ); - - let assign_result = Statement::Assignment( - "result".to_string(), - Box::new(Expression::FuncCall("gcd".to_string(), vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())])), - Some(TInteger), - ); - - let program = Statement::Sequence( - Box::new(assign_a), - Box::new(Statement::Sequence( - Box::new(assign_b), - Box::new(Statement::Sequence( - Box::new(func), - Box::new(assign_result), - )), - )), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some(&(Some(EnvValue::Exp(Expression::CInt(value))), _)) = new_env.get("result") { - assert_eq!(value, 6); - } else { - panic!("Variable 'result' not found or has incorrect type"); - } - } - Ok(_) => panic!("The interpreter did not continue execution as expected"), - Err(err) => panic!("Interpreter execution failed with error: {}", err), - } - } - - #[test] - fn metaexp_sqrt() { - /* - * Test for the r-python square root function (sqrt) using MetaExp - * - * Imaginary rpy code: - * - * > x: TReal = 25.0 - * > x = MetaExp(sqrt, [x], TReal) - * - * After execution, 'x' should be 5.0 (sqrt(25.0) = 5.0). - */ - - let env = Environment::new(); - - let assign_x = Statement::Assignment( - "x".to_string(), - Box::new(Expression::CReal(25.0)), - Some(Type::TReal), - ); - let meta_expr = Expression::MetaExp( - sqrt, - vec![Expression::Var("x".to_string())], - Type::TReal, - ); - - let assign_result = Statement::Assignment( - "x".to_string(), - Box::new(meta_expr), - Some(Type::TReal), - ); - - let program = Statement::Sequence( - Box::new(assign_x), - Box::new(assign_result), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some(&(Some(EnvValue::Exp(Expression::CReal(value))), _)) = new_env.get("x") { - assert_eq!(value, 5.0); - } else { - panic!("Variable 'x' not found or has incorrect type"); - } - } - Ok(_) => panic!("The interpreter did not continue execution as expected"), - Err(err) => panic!("Interpreter execution failed with error: {}", err), - } - } - - #[test] - fn metaexp_function_gcd() { - /* - * Test for the greatest common divisor function (gcd) using MetaStmt - * - * Imaginary rpy code: - * - * > a: TInteger = 48 - * > b: TInteger = 18 - * > def gcd(a: TInteger, b: TInteger) -> TInteger: - * > return MetaStmt(gcd, [a, b], TInteger) - * > result = gcd(a, b) - * - * After execution, 'result' should be 6 (gcd(48, 18) = 6). - */ - - let env = Environment::new(); - - let assign_a = Statement::Assignment( - "a".to_string(), - Box::new(Expression::CInt(48)), - Some(TInteger), - ); - - let assign_b = Statement::Assignment( - "b".to_string(), - Box::new(Expression::CInt(18)), - Some(TInteger), - ); - - let meta_epx = Expression::MetaExp( - gcd, - vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], - TInteger, - ); - - let func = Statement::FuncDef( - "gcd".to_string(), - Function { - kind: TInteger, - params: Some(vec![("a".to_string(), TInteger), ("b".to_string(), TInteger)]), - body: Box::new(Statement::Return(Box::new(meta_epx))), - }, - ); - - let assign_result = Statement::Assignment( - "result".to_string(), - Box::new(Expression::FuncCall("gcd".to_string(), vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())])), - Some(TInteger), - ); - - let program = Statement::Sequence( - Box::new(assign_a), - Box::new(Statement::Sequence( - Box::new(assign_b), - Box::new(Statement::Sequence( - Box::new(func), - Box::new(assign_result), - )), - )), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some(&(Some(EnvValue::Exp(Expression::CInt(value))), _)) = new_env.get("result") { - assert_eq!(value, 6); - } else { - panic!("Variable 'result' not found or has incorrect type"); - } - } - Ok(_) => panic!("The interpreter did not continue execution as expected"), - Err(err) => panic!("Interpreter execution failed with error: {}", err), - } - } - - /* - #[test] - fn metastmt_function_upper(){ - /* - * Test for the r-python square root function (sqrt) using MetaStmt - * - * Imaginary rpy code: - * - * > x: TString = "banana" - * > def upper(x: TString) -> TString: - * > MetaStmt(str_upper, [x], TString) - * > return metaResult - * > x = upper(x) - * - * After execution, 'x' should be 5.0 (sqrt(25.0) = 5.0). - */ - let env = Environment::new(); - let assign_x = Statement::Assignment( - "x".to_string(), - Box::new(Expression::CString("banana".to_string())), - Some(TString) - ); - let meta_stmt = Statement::MetaStmt( - str_upper, + sqrt_impl, vec![Expression::Var("x".to_string())], - TString - ); - let func = Statement::FuncDef( - "upper".to_string(), - Function{ - kind: TString, - params: Some(vec![("x".to_string(), TString)]), - body: Box::new(Sequence( - Box::new(meta_stmt), - Box::new(Return( - Box::new(Expression::Var("metaResult".to_string())) - )) - )) - } - ); - let assign_result = Statement::Assignment( - "x".to_string(), - Box::new(Expression::FuncCall("upper".to_string(), vec![Expression::Var("x".to_string())])), - Some(TString), - ); - let program = Statement::Sequence( - Box::new(assign_x), - Box::new(Statement::Sequence( - Box::new(func), - Box::new(assign_result) - )) - ); - match execute(program, &env, true){ - Ok(ControlFlow::Continue(new_env)) => { - if let Some(&(Some(EnvValue::Exp(Expression::CString(ref value))), _)) = new_env.get("x"){ - assert_eq!(value, &"BANANA".to_string()); - } else{ - panic!("Variable 'x' not found or has incorret type"); - } - - } - Ok(_) => panic!("The interpreter did not continue execution as expect"), - Err(err) => panic!("Interpreter execution failed with error: {}", err), - - } - } - */ - #[test] - fn metastmt_function_upper() { - /* - * Teste para a função de conversão de string para maiúsculas usando MetaStmt - * - * Código imaginário em rpy: - * - * > x: TString = "hello" - * > def upper(x: TString) -> TString: - * > MetaStmt(str_upper, [x], TString) - * > return metaResult - * > result = upper(x) - * - * Após a execução, 'result' deve ser "HELLO". - */ - let env = HashMap::new(); - let program = Statement::Sequence( - Box::new(Statement::Assignment( - "x".to_string(), - Box::new(Expression::CString("hello".to_string())), - Some(Type::TString), - )), - Box::new(Statement::MetaStmt( - str_upper, - vec![Expression::Var("x".to_string())], - Type::TString, - )), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some((Some(EnvValue::Exp(Expression::CString(result))), _)) = new_env.get("metaResult") { - assert_eq!(result, "HELLO"); - } else { - panic!("metaResult not found or invalid type"); - } - } - _ => panic!("Test failed"), - } - } - - #[test] - fn metastmt_function_lower() { - /* - * Teste para a função de conversão de string para minúsculas usando MetaStmt - * - * Código imaginário em rpy: - * - * > x: TString = "HELLO" - * > def lower(x: TString) -> TString: - * > MetaStmt(str_lower, [x], TString) - * > return metaResult - * > result = lower(x) - * - * Após a execução, 'result' deve ser "hello". - */ - let env = HashMap::new(); - let program = Statement::Sequence( - Box::new(Statement::Assignment( - "x".to_string(), - Box::new(Expression::CString("HELLO".to_string())), - Some(Type::TString), - )), - Box::new(Statement::MetaStmt( - str_lower, - vec![Expression::Var("x".to_string())], - Type::TString, - )), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some((Some(EnvValue::Exp(Expression::CString(result))), _)) = new_env.get("metaResult") { - assert_eq!(result, "hello"); - } else { - panic!("metaResult not found or invalid type"); - } - } - _ => panic!("Test failed"), - } - } - - #[test] - fn metastmt_function_length() { - /* - * Teste para a função de obtenção do comprimento de uma string usando MetaStmt - * - * Código imaginário em rpy: - * - * > x: TString = "hello" - * > def length(x: TString) -> TInteger: - * > MetaStmt(str_length, [x], TInteger) - * > return metaResult - * > result = length(x) - * - * Após a execução, 'result' deve ser 5. - */ - let env = HashMap::new(); - let program = Statement::Sequence( - Box::new(Statement::Assignment( - "x".to_string(), - Box::new(Expression::CString("hello".to_string())), - Some(Type::TString), - )), - Box::new(Statement::MetaStmt( - str_length, - vec![Expression::Var("x".to_string())], - Type::TInteger, - )), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some((Some(EnvValue::Exp(Expression::CInt(result))), _)) = new_env.get("metaResult") { - assert_eq!(*result, 5); - } else { - panic!("metaResult not found or invalid type"); - } - } - _ => panic!("Test failed"), - } - } - - #[test] - fn metastmt_function_reverse() { - /* - * Teste para a função de reversão de string usando MetaStmt - * - * Código imaginário em rpy: - * - * > x: TString = "hello" - * > def reverse(x: TString) -> TString: - * > MetaStmt(str_reverse, [x], TString) - * > return metaResult - * > result = reverse(x) - * - * Após a execução, 'result' deve ser "olleh". - */ - let env = HashMap::new(); - let program = Statement::Sequence( - Box::new(Statement::Assignment( - "x".to_string(), - Box::new(Expression::CString("hello".to_string())), - Some(Type::TString), - )), - Box::new(Statement::MetaStmt( - str_reverse, - vec![Expression::Var("x".to_string())], - Type::TString, - )), + Type::TReal ); - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some((Some(EnvValue::Exp(Expression::CString(result))), _)) = new_env.get("metaResult") { - assert_eq!(result, "olleh"); - } else { - panic!("metaResult not found or invalid type"); - } - } - _ => panic!("Test failed"), + let result = eval(meta_expr, &env).expect("Evaluation failed"); + match result { + EnvValue::Exp(Expression::CReal(value)) => assert_eq!(value, 5.0), + _ => panic!("Expected a CReal with value 5.0"), } } - - #[test] - fn metastmt_function_cont_chars() { - /* - * Teste para a função de contagem de caracteres usando MetaStmt - * - * Código imaginário em rpy: - * - * > s: TString = "banana" - * > c: TString = "a" - * > def cont_chars(s: TString, c: TString) -> TInteger: - * > MetaStmt(cont_chars, [s, c], TInteger) - * > return metaResult - * > result = cont_chars(s, c) - * - * Após a execução, 'result' deve ser 3. - */ - let env = HashMap::new(); - let program = Statement::Sequence( - Box::new(Statement::Assignment( - "s".to_string(), - Box::new(Expression::CString("banana".to_string())), - Some(Type::TString), - )), - Box::new(Statement::Sequence( - Box::new(Statement::Assignment( - "c".to_string(), - Box::new(Expression::CString("a".to_string())), - Some(Type::TString), - )), - Box::new(Statement::MetaStmt( - cont_chars, - vec![Expression::Var("s".to_string()), Expression::Var("c".to_string())], - Type::TInteger, - )), - )), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some((Some(EnvValue::Exp(Expression::CInt(result))), _)) = new_env.get("metaResult") { - assert_eq!(*result, 3); - } else { - panic!("metaResult not found or invalid type"); - } - } - _ => panic!("Test failed"), - } - } - - #[test] - fn metastmt_function_filter_out_char() { - /* - * Teste para a função de remoção de um caractere específico de uma string usando MetaStmt - * - * Código imaginário em rpy: - * - * > s: TString = "banana" - * > c: TString = "a" - * > def filter_out_char(s: TString, c: TString) -> TString: - * > MetaStmt(filter_out_char, [s, c], TString) - * > return metaResult - * > result = filter_out_char(s, c) - * - * Após a execução, 'result' deve ser "bnn". - */ - let env = HashMap::new(); - let program = Statement::Sequence( - Box::new(Statement::Assignment( - "s".to_string(), - Box::new(Expression::CString("banana".to_string())), - Some(Type::TString), - )), - Box::new(Statement::Sequence( - Box::new(Statement::Assignment( - "c".to_string(), - Box::new(Expression::CString("a".to_string())), - Some(Type::TString), - )), - Box::new(Statement::MetaStmt( - filter_out_char, - vec![Expression::Var("s".to_string()), Expression::Var("c".to_string())], - Type::TString, - )), - )), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some((Some(EnvValue::Exp(Expression::CString(result))), _)) = new_env.get("metaResult") { - assert_eq!(result, "bnn"); - } else { - panic!("metaResult not found or invalid type"); - } - } - _ => panic!("Test failed"), - } - } - - #[test] - fn metastmt_function_replace() { - /* - * Teste para a função de substituição de caracteres em uma string usando MetaStmt - * - * Código imaginário em rpy: - * - * > s: TString = "banana" - * > old: TString = "a" - * > new: TString = "o" - * > def replace(s: TString, old: TString, new: TString) -> TString: - * > MetaStmt(replace, [s, old, new], TString) - * > return metaResult - * > result = replace(s, old, new) - * - * Após a execução, 'result' deve ser "bonono". - */ - let env = HashMap::new(); - let program = Statement::Sequence( - Box::new(Statement::Assignment( - "s".to_string(), - Box::new(Expression::CString("banana".to_string())), - Some(Type::TString), - )), - Box::new(Statement::Sequence( - Box::new(Statement::Assignment( - "old".to_string(), - Box::new(Expression::CString("a".to_string())), - Some(Type::TString), - )), - Box::new(Statement::Sequence( - Box::new(Statement::Assignment( - "new".to_string(), - Box::new(Expression::CString("o".to_string())), - Some(Type::TString), - )), - Box::new(Statement::MetaStmt( - replace, - vec![ - Expression::Var("s".to_string()), - Expression::Var("old".to_string()), - Expression::Var("new".to_string()), - ], - Type::TString, - )), - )), - )), - ); - - match execute(program, &env, true) { - Ok(ControlFlow::Continue(new_env)) => { - if let Some((Some(EnvValue::Exp(Expression::CString(result))), _)) = new_env.get("metaResult") { - assert_eq!(result, "bonono"); - } else { - panic!("metaResult not found or invalid type"); - } - } - _ => panic!("Test failed"), - } - } - } diff --git a/src/ir/ast.rs b/src/ir/ast.rs index 4c914ec..cc5b7f9 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -75,7 +75,6 @@ pub enum Statement { Sequence(Box, Box), FuncDef(Name, Function), Return(Box), - MetaStmt(fn(Vec) -> Result, Vec, Type), } #[derive(Debug)] diff --git a/src/parser/parser.rs b/src/parser/parser.rs index e15c866..8e46ce0 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -14,9 +14,6 @@ type ParseResult<'a, T> = IResult<&'a str, T, Error<&'a str>>; use crate::ir::ast::Function; use crate::ir::ast::Type; use crate::ir::ast::{Expression, Name, Statement}; -use crate::stdlib::math::*; -use crate::stdlib::string::*; -use crate::ir::ast::EnvValue; // Parse identifier fn identifier(input: &str) -> IResult<&str, Name> { @@ -72,7 +69,6 @@ fn term(input: &str) -> ParseResult { fn statement(input: &str) -> IResult<&str, Statement> { let (input, _) = space0(input)?; alt(( - meta_stmt, function_def, if_statement, return_statement, @@ -84,7 +80,6 @@ fn statement(input: &str) -> IResult<&str, Statement> { // Parse basic expressions fn expression(input: &str) -> IResult<&str, Expression> { alt(( - meta_exp, boolean_expression, comparison_expression, arithmetic_expression, @@ -375,76 +370,6 @@ fn return_statement(input: &str) -> IResult<&str, Statement> { Ok((input, Statement::Return(Box::new(expr)))) } -//meta parsing -fn meta_exp(input: &str) -> IResult<&str, Expression> { - let (input, _) = tag("MetaExp")(input)?; - let (input, _) = space0(input)?; - let (input, _) = char('(')(input)?; - let (input, meta_func_id) = identifier(input)?; - let (input, _) = delimited(space0, char(','), space0)(input)?; - let (input, args) = delimited( - char('['), - separated_list0(delimited(space0, char(','), space0), expression), - char(']') - )(input)?; - let (input, _) = delimited(space0, char(','), space0)(input)?; - let (input, type_str) = identifier(input)?; - let (input, _) = char(')')(input)?; - - let meta_func = match resolve_meta_function(&meta_func_id) { - Ok(func) => func, - Err(_) => return Err(nom::Err::Failure(Error::new(input, ErrorKind::Tag))), - }; - let meta_type = parse_type(&type_str); - - Ok((input, Expression::MetaExp(meta_func, args, meta_type))) -} - -fn meta_stmt(input: &str) -> IResult<&str, Statement> { - let (input, _) = tag("MetaStmt")(input)?; - let (input, _) = space0(input)?; - let (input, _) = char('(')(input)?; - let (input, meta_func_id) = identifier(input)?; - let (input, _) = delimited(space0, char(','), space0)(input)?; - let (input, args) = delimited( - char('['), - separated_list0(delimited(space0, char(','), space0), expression), - char(']') - )(input)?; - let (input, _) = delimited(space0, char(','), space0)(input)?; - let (input, type_str) = identifier(input)?; - let (input, _) = char(')')(input)?; - - let meta_func = match resolve_meta_function(&meta_func_id) { - Ok(func) => func, - Err(_) => return Err(nom::Err::Failure(Error::new(input, ErrorKind::Tag))), - }; - let meta_type = parse_type(&type_str); - - Ok((input, Statement::MetaStmt(meta_func, args, meta_type))) -} - -fn resolve_meta_function(id: &str) -> Result) -> Result, String> { - match id { - "sqrt" => Ok(sqrt), - "factorial" => Ok(factorial), - "gcd" => Ok(gcd), - "lcm" => Ok(lcm), - "comb" => Ok(comb), - "perm" => Ok(perm), - "is_prime" => Ok(is_prime), - "log" => Ok(log), - "str_upper" => Ok(str_upper), - "str_lower" => Ok(str_lower), - "str_length" => Ok(str_length), - "str_reverse" => Ok(str_reverse), - "cont_chars" => Ok(cont_chars), - "filter_out_char" => Ok(filter_out_char), - "replace" => Ok(replace), - _ => Err(format!("Meta function '{}' não encontrada", id)), - } -} - // Parse multiple statements pub fn parse_statements(input: &str) -> IResult<&str, Vec> { let (input, _) = space0(input)?; // Handle initial whitespace @@ -959,49 +884,4 @@ mod tests { assert_eq!(rest, ""); assert_eq!(result, expected); } - - #[test] - fn test_metaexp_parsing() { - let input = "x = MetaExp(sqrt, [x], TReal)"; - let (rest, stmts) = parse(input).unwrap(); - assert_eq!(rest, ""); - - match &stmts[0] { - Statement::Assignment(name, expr, _type) => { - assert_eq!(name, "x"); - match &**expr { - Expression::MetaExp(_, args, meta_type) => { - assert_eq!(meta_type, &Type::TReal); - assert_eq!(args.len(), 1); - match &args[0] { - Expression::Var(var_name) => assert_eq!(var_name, "x"), - _ => panic!("Expected a variable as argument in MetaExp"), - } - }, - _ => panic!("Expected a MetaExp expression"), - } - }, - _ => panic!("Expected an Assignment statement"), - } - } - - #[test] - fn test_metastmt_parsing() { - let input = "MetaStmt(sqrt, [x], TReal)"; - let (rest, stmt) = meta_stmt(input).unwrap(); - assert_eq!(rest, ""); - - match stmt { - Statement::MetaStmt(_, args, meta_type) => { - assert_eq!(meta_type, Type::TReal); - assert_eq!(args.len(), 1); - match &args[0] { - Expression::Var(var_name) => assert_eq!(var_name, "x"), - _ => panic!("Expected a variable as argument in MetaStmt"), - } - }, - _ => panic!("Expected a MetaStmt statement"), - } - } - } diff --git a/src/stdlib.rs b/src/stdlib.rs index 73beb73..2d5d6e4 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -1,2 +1,3 @@ pub mod math; -pub mod string; \ No newline at end of file +pub mod string; +pub mod stdlib; \ No newline at end of file diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs index 9483697..0e2d379 100644 --- a/src/stdlib/math.rs +++ b/src/stdlib/math.rs @@ -1,7 +1,86 @@ -use crate::ir::ast::{EnvValue, Expression}; - +use std::collections::HashMap; +use crate::ir::ast::{EnvValue, Expression, Function, Statement, Type}; + + +pub fn load_math_stdlib() -> HashMap { + let mut math_stdlib = HashMap::new(); + + math_stdlib.insert( + "sqrt".to_string(), + Function { + kind: Type::TReal, + params: Some(vec![("x".to_string(), Type::TReal)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(sqrt_impl, vec![Expression::Var("x".to_string())], Type::TReal)))), + } + ); + + math_stdlib.insert( + "factorial".to_string(), + Function { + kind: Type::TInteger, + params: Some(vec![("n".to_string(), Type::TInteger)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(factorial_impl, vec![Expression::Var("x".to_string())], Type::TInteger)))), + } + ); + + math_stdlib.insert( + "gcd".to_string(), + Function { + kind: Type::TInteger, + params: Some(vec![("a".to_string(), Type::TInteger), ("b".to_string(), Type::TInteger)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(gcd_impl, vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], Type::TInteger)))), + } + ); + + math_stdlib.insert( + "lcm".to_string(), + Function { + kind: Type::TInteger, + params: Some(vec![("a".to_string(), Type::TInteger), ("b".to_string(), Type::TInteger)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(lcm_impl, vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], Type::TInteger)))), + } + ); + + math_stdlib.insert( + "is_prime".to_string(), + Function { + kind: Type::TBool, + params: Some(vec![("x".to_string(), Type::TInteger)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(is_prime_impl, vec![Expression::Var("x".to_string())], Type::TBool)))), + } + ); + + math_stdlib.insert( + "comb".to_string(), + Function { + kind: Type::TInteger, + params: Some(vec![("n".to_string(), Type::TInteger), ("k".to_string(), Type::TInteger)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(comb_impl, vec![Expression::Var("n".to_string()), Expression::Var("r".to_string())], Type::TInteger)))) + } + ); + + math_stdlib.insert( + "perm".to_string(), + Function { + kind: Type::TInteger, + params: Some(vec![("n".to_string(), Type::TInteger), ("k".to_string(), Type::TInteger)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(perm_impl, vec![Expression::Var("n".to_string()), Expression::Var("r".to_string())], Type::TInteger)))) + } + ); + + math_stdlib.insert( + "log".to_string(), + Function { + kind: Type::TReal, + params: Some(vec![("x".to_string(), Type::TReal), ("base".to_string(), Type::TReal)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(log_impl, vec![Expression::Var("x".to_string()), Expression::Var("base".to_string())], Type::TReal)))) + } + ); + + math_stdlib +} -pub fn sqrt(args: Vec) -> Result { +pub fn sqrt_impl(args: Vec) -> Result { if args.len() != 1 { return Err("sqrt expects exactly one argument".to_string()); } @@ -13,7 +92,7 @@ pub fn sqrt(args: Vec) -> Result { } } -pub fn factorial(args: Vec) -> Result { +pub fn factorial_impl(args: Vec) -> Result { if args.len() != 1 { return Err("factorial expects exactly one argument".to_string()); } @@ -32,7 +111,7 @@ pub fn factorial(args: Vec) -> Result { } } -pub fn gcd(args: Vec) -> Result { +pub fn gcd_impl(args: Vec) -> Result { if args.len() != 2 { return Err("gcd expects exactly two arguments".to_string()); } @@ -54,7 +133,7 @@ pub fn gcd(args: Vec) -> Result { } -pub fn lcm(args: Vec) -> Result { +pub fn lcm_impl(args: Vec) -> Result { if args.len() != 2 { return Err("lcm expects exactly two arguments".to_string()); } @@ -62,7 +141,7 @@ pub fn lcm(args: Vec) -> Result { if let (EnvValue::Exp(Expression::CInt(a)), EnvValue::Exp(Expression::CInt(b))) = (&args[0], &args[1]) { - let gcd_val = match gcd(args.clone()) { + let gcd_val = match gcd_impl(args.clone()) { Ok(EnvValue::Exp(Expression::CInt(val))) => val, Err(err) => return Err(format!("Error calculating gcd: {}", err)), _ => return Err("Unexpected error in gcd calculation".to_string()), @@ -75,7 +154,7 @@ pub fn lcm(args: Vec) -> Result { } } -pub fn comb(args: Vec) -> Result { +pub fn comb_impl(args: Vec) -> Result { if args.len() != 2 { return Err("comb expects exactly two arguments".to_string()); } @@ -99,7 +178,7 @@ pub fn comb(args: Vec) -> Result { } } -pub fn perm(args: Vec) -> Result { +pub fn perm_impl(args: Vec) -> Result { if args.len() != 2 { return Err("perm expects exactly two arguments".to_string()); } @@ -123,7 +202,7 @@ pub fn perm(args: Vec) -> Result { } } -pub fn is_prime(args: Vec) -> Result { +pub fn is_prime_impl(args: Vec) -> Result { if args.len() != 1 { return Err("is_prime expects exactly one argument".to_string()); } @@ -164,7 +243,7 @@ pub fn is_prime(args: Vec) -> Result { } -pub fn log(args: Vec) -> Result { +pub fn log_impl(args: Vec) -> Result { if args.len() != 2 { return Err("log expects exactly two arguments".to_string()); } @@ -185,19 +264,19 @@ mod tests { //TESTES FUNCAO SQRT #[test] fn test_sqrt_positive_real() { - let result = sqrt(vec![EnvValue::Exp(Expression::CReal(9.0))]); + let result = sqrt_impl(vec![EnvValue::Exp(Expression::CReal(9.0))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CReal(res_value))) = result { assert_eq!(res_value, 3.0); } - let result = sqrt(vec![EnvValue::Exp(Expression::CReal(49.0))]); + let result = sqrt_impl(vec![EnvValue::Exp(Expression::CReal(49.0))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CReal(res_value))) = result { assert_eq!(res_value, 7.0); } - let result = sqrt(vec![EnvValue::Exp(Expression::CReal(121.0))]); + let result = sqrt_impl(vec![EnvValue::Exp(Expression::CReal(121.0))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CReal(res_value))) = result { assert_eq!(res_value, 11.0); @@ -206,7 +285,7 @@ mod tests { #[test] fn test_sqrt_zero() { - let result = sqrt(vec![EnvValue::Exp(Expression::CReal(0.0))]); + let result = sqrt_impl(vec![EnvValue::Exp(Expression::CReal(0.0))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CReal(res_value))) = result { assert_eq!(res_value, 0.0); @@ -215,14 +294,14 @@ mod tests { #[test] fn test_sqrt_invalid_number_of_arguments() { - let result = sqrt(vec![]); + let result = sqrt_impl(vec![]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "sqrt expects exactly one argument"); } #[test] fn test_sqrt_invalid_number_of_arguments_multiple() { - let result = sqrt(vec![ + let result = sqrt_impl(vec![ EnvValue::Exp(Expression::CReal(25.0)), EnvValue::Exp(Expression::CReal(9.0)), ]); @@ -232,32 +311,32 @@ mod tests { #[test] fn test_sqrt_invalid_argument_type() { - let result = sqrt(vec![EnvValue::Exp(Expression::CInt(25))]); + let result = sqrt_impl(vec![EnvValue::Exp(Expression::CInt(25))]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "sqrt expects a real number argument"); } //TESTES FUNCAO FACTORIAL #[test] fn test_factorial_valid_inputs() { - let result = factorial(vec![EnvValue::Exp(Expression::CInt(0))]); + let result = factorial_impl(vec![EnvValue::Exp(Expression::CInt(0))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { assert_eq!(value, 1); } - let result = factorial(vec![EnvValue::Exp(Expression::CInt(1))]); + let result = factorial_impl(vec![EnvValue::Exp(Expression::CInt(1))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { assert_eq!(value, 1); } - let result = factorial(vec![EnvValue::Exp(Expression::CInt(5))]); + let result = factorial_impl(vec![EnvValue::Exp(Expression::CInt(5))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { assert_eq!(value, 120); } - let result = factorial(vec![EnvValue::Exp(Expression::CInt(10))]); + let result = factorial_impl(vec![EnvValue::Exp(Expression::CInt(10))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CInt(value))) = result { assert_eq!(value, 3628800); @@ -266,14 +345,14 @@ mod tests { #[test] fn test_factorial_invalid_number_of_arguments() { - let result = factorial(vec![]); + let result = factorial_impl(vec![]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "factorial expects exactly one argument"); } #[test] fn test_factorial_invalid_number_of_arguments_multiple() { - let result = factorial(vec![ + let result = factorial_impl(vec![ EnvValue::Exp(Expression::CInt(1)), EnvValue::Exp(Expression::CInt(2)), ]); @@ -283,21 +362,21 @@ mod tests { #[test] fn test_factorial_invalid_argument_type() { - let result = factorial(vec![EnvValue::Exp(Expression::CReal(3.5))]); + let result = factorial_impl(vec![EnvValue::Exp(Expression::CReal(3.5))]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "factorial expects an integer argument"); } #[test] fn test_factorial_negative_argument() { - let result = factorial(vec![EnvValue::Exp(Expression::CInt(-1))]); + let result = factorial_impl(vec![EnvValue::Exp(Expression::CInt(-1))]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "factorial expects a non-negative integer argument"); } //TESTES FUNCAO GCD #[test] fn test_gcd_valid_inputs() { - let result = gcd(vec![ + let result = gcd_impl(vec![ EnvValue::Exp(Expression::CInt(48)), EnvValue::Exp(Expression::CInt(18)), ]); @@ -306,7 +385,7 @@ mod tests { assert_eq!(value, 6); } - let result = gcd(vec![ + let result = gcd_impl(vec![ EnvValue::Exp(Expression::CInt(7)), EnvValue::Exp(Expression::CInt(3)), ]); @@ -315,7 +394,7 @@ mod tests { assert_eq!(value, 1); } - let result = gcd(vec![ + let result = gcd_impl(vec![ EnvValue::Exp(Expression::CInt(-48)), EnvValue::Exp(Expression::CInt(18)), ]); @@ -324,7 +403,7 @@ mod tests { assert_eq!(value, 6); } - let result = gcd(vec![ + let result = gcd_impl(vec![ EnvValue::Exp(Expression::CInt(0)), EnvValue::Exp(Expression::CInt(18)), ]); @@ -336,14 +415,14 @@ mod tests { #[test] fn test_gcd_invalid_number_of_arguments() { - let result = gcd(vec![EnvValue::Exp(Expression::CInt(48))]); + let result = gcd_impl(vec![EnvValue::Exp(Expression::CInt(48))]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "gcd expects exactly two arguments"); } #[test] fn test_gcd_invalid_number_of_arguments_multiple() { - let result = gcd(vec![ + let result = gcd_impl(vec![ EnvValue::Exp(Expression::CInt(48)), EnvValue::Exp(Expression::CInt(18)), EnvValue::Exp(Expression::CInt(6)), @@ -354,7 +433,7 @@ mod tests { #[test] fn test_gcd_invalid_argument_type() { - let result = gcd(vec![ + let result = gcd_impl(vec![ EnvValue::Exp(Expression::CReal(48.0)), EnvValue::Exp(Expression::CInt(18)), ]); @@ -364,7 +443,7 @@ mod tests { //TESTES PARA LCM #[test] fn test_lcm_valid_inputs() { - let result = lcm(vec![ + let result = lcm_impl(vec![ EnvValue::Exp(Expression::CInt(48)), EnvValue::Exp(Expression::CInt(18)), ]); @@ -373,7 +452,7 @@ mod tests { assert_eq!(value, 144); } - let result = lcm(vec![ + let result = lcm_impl(vec![ EnvValue::Exp(Expression::CInt(7)), EnvValue::Exp(Expression::CInt(3)), ]); @@ -382,7 +461,7 @@ mod tests { assert_eq!(value, 21); } - let result = lcm(vec![ + let result = lcm_impl(vec![ EnvValue::Exp(Expression::CInt(-48)), EnvValue::Exp(Expression::CInt(18)), ]); @@ -391,7 +470,7 @@ mod tests { assert_eq!(value, 144); } - let result = lcm(vec![ + let result = lcm_impl(vec![ EnvValue::Exp(Expression::CInt(0)), EnvValue::Exp(Expression::CInt(18)), ]); @@ -403,14 +482,14 @@ mod tests { #[test] fn test_lcm_invalid_number_of_arguments() { - let result = lcm(vec![EnvValue::Exp(Expression::CInt(48))]); + let result = lcm_impl(vec![EnvValue::Exp(Expression::CInt(48))]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "lcm expects exactly two arguments"); } #[test] fn test_lcm_invalid_number_of_arguments_multiple() { - let result = lcm(vec![ + let result = lcm_impl(vec![ EnvValue::Exp(Expression::CInt(48)), EnvValue::Exp(Expression::CInt(18)), EnvValue::Exp(Expression::CInt(6)), @@ -421,7 +500,7 @@ mod tests { #[test] fn test_lcm_invalid_argument_type() { - let result = lcm(vec![ + let result = lcm_impl(vec![ EnvValue::Exp(Expression::CReal(48.0)), EnvValue::Exp(Expression::CInt(18)), ]); @@ -432,7 +511,7 @@ mod tests { //TESTES PARA COMB #[test] fn test_comb_valid_inputs() { - let result = comb(vec![ + let result = comb_impl(vec![ EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(2)), ]); @@ -441,7 +520,7 @@ mod tests { assert_eq!(value, 10); } - let result = comb(vec![ + let result = comb_impl(vec![ EnvValue::Exp(Expression::CInt(10)), EnvValue::Exp(Expression::CInt(3)), ]); @@ -450,7 +529,7 @@ mod tests { assert_eq!(value, 120); } - let result = comb(vec![ + let result = comb_impl(vec![ EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(6)), ]); @@ -462,14 +541,14 @@ mod tests { #[test] fn test_comb_invalid_number_of_arguments() { - let result = comb(vec![EnvValue::Exp(Expression::CInt(5))]); + let result = comb_impl(vec![EnvValue::Exp(Expression::CInt(5))]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "comb expects exactly two arguments"); } #[test] fn test_comb_invalid_number_of_arguments_multiple() { - let result = comb(vec![ + let result = comb_impl(vec![ EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(2)), EnvValue::Exp(Expression::CInt(1)), @@ -480,7 +559,7 @@ mod tests { #[test] fn test_comb_invalid_argument_type() { - let result = comb(vec![ + let result = comb_impl(vec![ EnvValue::Exp(Expression::CReal(5.0)), EnvValue::Exp(Expression::CInt(2)), ]); @@ -490,7 +569,7 @@ mod tests { #[test] fn test_comb_negative_arguments() { - let result = comb(vec![ + let result = comb_impl(vec![ EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(-2)), ]); @@ -501,7 +580,7 @@ mod tests { //TESTES PARA PERM #[test] fn test_perm_valid_inputs() { - let result = perm(vec![ + let result = perm_impl(vec![ EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(2)), ]); @@ -510,7 +589,7 @@ mod tests { assert_eq!(value, 20); } - let result = perm(vec![ + let result = perm_impl(vec![ EnvValue::Exp(Expression::CInt(10)), EnvValue::Exp(Expression::CInt(3)), ]); @@ -519,7 +598,7 @@ mod tests { assert_eq!(value, 720); } - let result = perm(vec![ + let result = perm_impl(vec![ EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(6)), ]); @@ -531,14 +610,14 @@ mod tests { #[test] fn test_perm_invalid_number_of_arguments() { - let result = perm(vec![EnvValue::Exp(Expression::CInt(5))]); + let result = perm_impl(vec![EnvValue::Exp(Expression::CInt(5))]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "perm expects exactly two arguments"); } #[test] fn test_perm_invalid_number_of_arguments_multiple() { - let result = perm(vec![ + let result = perm_impl(vec![ EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(2)), EnvValue::Exp(Expression::CInt(1)), @@ -549,7 +628,7 @@ mod tests { #[test] fn test_perm_invalid_argument_type() { - let result = perm(vec![ + let result = perm_impl(vec![ EnvValue::Exp(Expression::CReal(5.0)), EnvValue::Exp(Expression::CInt(2)), ]); @@ -559,7 +638,7 @@ mod tests { #[test] fn test_perm_negative_arguments() { - let result = perm(vec![ + let result = perm_impl(vec![ EnvValue::Exp(Expression::CInt(5)), EnvValue::Exp(Expression::CInt(-2)), ]); @@ -570,31 +649,31 @@ mod tests { //================================================================================================= #[test] fn test_is_prime_valid_inputs() { - let result = is_prime(vec![EnvValue::Exp(Expression::CInt(2))]); + let result = is_prime_impl(vec![EnvValue::Exp(Expression::CInt(2))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CTrue)) = result { assert!(true); } - let result = is_prime(vec![EnvValue::Exp(Expression::CInt(3))]); + let result = is_prime_impl(vec![EnvValue::Exp(Expression::CInt(3))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CTrue)) = result { assert!(true); } - let result = is_prime(vec![EnvValue::Exp(Expression::CInt(7))]); + let result = is_prime_impl(vec![EnvValue::Exp(Expression::CInt(7))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CTrue)) = result { assert!(true); } - let result = is_prime(vec![EnvValue::Exp(Expression::CInt(13))]); + let result = is_prime_impl(vec![EnvValue::Exp(Expression::CInt(13))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CTrue)) = result { assert!(true); } - let result = is_prime(vec![EnvValue::Exp(Expression::CInt(17))]); + let result = is_prime_impl(vec![EnvValue::Exp(Expression::CInt(17))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CTrue)) = result { assert!(true); @@ -603,14 +682,14 @@ mod tests { #[test] fn test_is_prime_invalid_number_of_arguments() { - let result = is_prime(vec![]); + let result = is_prime_impl(vec![]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "is_prime expects exactly one argument"); } #[test] fn test_is_prime_invalid_number_of_arguments_multiple() { - let result = is_prime(vec![ + let result = is_prime_impl(vec![ EnvValue::Exp(Expression::CInt(2)), EnvValue::Exp(Expression::CInt(3)), ]); @@ -620,14 +699,14 @@ mod tests { #[test] fn test_is_prime_invalid_argument_type() { - let result = is_prime(vec![EnvValue::Exp(Expression::CReal(2.0))]); + let result = is_prime_impl(vec![EnvValue::Exp(Expression::CReal(2.0))]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "is_prime expects an integer argument"); } #[test] fn test_is_prime_negative_argument() { - let result = is_prime(vec![EnvValue::Exp(Expression::CInt(-1))]); + let result = is_prime_impl(vec![EnvValue::Exp(Expression::CInt(-1))]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "is_prime expects a non-negative integer"); } @@ -635,7 +714,7 @@ mod tests { //================================================================================================= #[test] fn test_log_valid_inputs() { - let result = log(vec![ + let result = log_impl(vec![ EnvValue::Exp(Expression::CReal(10.0)), EnvValue::Exp(Expression::CReal(100.0)), ]); @@ -644,7 +723,7 @@ mod tests { assert_eq!(value, 2.0); } - let result = log(vec![ + let result = log_impl(vec![ EnvValue::Exp(Expression::CReal(2.0)), EnvValue::Exp(Expression::CReal(8.0)), ]); @@ -653,7 +732,7 @@ mod tests { assert_eq!(value, 3.0); } - let result = log(vec![ + let result = log_impl(vec![ EnvValue::Exp(Expression::CReal(10.0)), EnvValue::Exp(Expression::CReal(10000.0)), ]); @@ -665,14 +744,14 @@ mod tests { #[test] fn test_log_invalid_number_of_arguments() { - let result = log(vec![EnvValue::Exp(Expression::CReal(10.0))]); + let result = log_impl(vec![EnvValue::Exp(Expression::CReal(10.0))]); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "log expects exactly two arguments"); } #[test] fn test_log_invalid_number_of_arguments_multiple() { - let result = log(vec![ + let result = log_impl(vec![ EnvValue::Exp(Expression::CReal(10.0)), EnvValue::Exp(Expression::CReal(100.0)), EnvValue::Exp(Expression::CReal(10.0)), @@ -683,7 +762,7 @@ mod tests { #[test] fn test_log_invalid_argument_type() { - let result = log(vec![ + let result = log_impl(vec![ EnvValue::Exp(Expression::CInt(10)), EnvValue::Exp(Expression::CReal(100.0)), ]); diff --git a/src/stdlib/stdlib.rs b/src/stdlib/stdlib.rs new file mode 100644 index 0000000..d7688d1 --- /dev/null +++ b/src/stdlib/stdlib.rs @@ -0,0 +1,438 @@ +use std::collections::HashMap; +use crate::ir::ast::Function; + +use crate::stdlib::math::load_math_stdlib; +use crate::stdlib::string::load_string_stdlib; + +pub fn load_stdlib() -> HashMap { + let mut stdlib = HashMap::new(); + + let math_stdlib = load_math_stdlib(); + for (name, func) in math_stdlib { + stdlib.insert(name, func); + } + + let string_stdlib = load_string_stdlib(); + for (name, func) in string_stdlib { + stdlib.insert(name, func); + } + + stdlib +} + +#[cfg(test)] +mod stdlib_tests { + use crate::ir::ast::{Statement, Expression, Type}; + use crate::stdlib::math::load_math_stdlib; + use crate::stdlib::string::load_string_stdlib; + + #[test] + fn test_load_math_stdlib_contains_sqrt() { + let math_stdlib = load_math_stdlib(); + let sqrt_func = math_stdlib.get("sqrt").expect("Function 'sqrt' not found in math stdlib"); + + assert_eq!(sqrt_func.kind, Type::TReal); + + let params = sqrt_func.params.as_ref().expect("Expected parameters for sqrt"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "x"); + assert_eq!(params[0].1, Type::TReal); + + match *sqrt_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); + }, + _ => panic!("Expected MetaExp inside Return for sqrt"), + } + }, + _ => panic!("Expected Return statement for sqrt body"), + } + } + + #[test] + fn test_load_math_stdlib_contains_factorial(){ + let math_stdlib = load_math_stdlib(); + let factorial_func = math_stdlib.get("factorial").expect("Function 'factorial' not found in math stdlib"); + + assert_eq!(factorial_func.kind, Type::TInteger); + + let params = factorial_func.params.as_ref().expect("Expected parameters for factorial"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "n"); + assert_eq!(params[0].1, Type::TInteger); + + match *factorial_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TInteger); + }, + _ => panic!("Expected MetaExp inside Return for factorial"), + } + }, + _ => panic!("Expected Return statement for factorial body"), + } + } + + #[test] + fn test_load_math_stdlib_contains_gcd(){ + let math_stdlib = load_math_stdlib(); + let gcd_func = math_stdlib.get("gcd").expect("Function 'gcd' not found in math stdlib"); + + assert_eq!(gcd_func.kind, Type::TInteger); + + let params = gcd_func.params.as_ref().expect("Expected parameters for gcd"); + assert_eq!(params.len(), 2); + assert_eq!(params[0].0, "a"); + assert_eq!(params[0].1, Type::TInteger); + assert_eq!(params[1].0, "b"); + assert_eq!(params[1].1, Type::TInteger); + + match *gcd_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TInteger); + }, + _ => panic!("Expected MetaExp inside Return for gcd"), + } + }, + _ => panic!("Expected Return statement for gcd body"), + } + } + + #[test] + fn test_load_math_stdlib_contains_lcm(){ + let math_stdlib = load_math_stdlib(); + let lcm_func = math_stdlib.get("lcm").expect("Function 'lcm' not found in math stdlib"); + + assert_eq!(lcm_func.kind, Type::TInteger); + + let params = lcm_func.params.as_ref().expect("Expected parameters for lcm"); + assert_eq!(params.len(), 2); + assert_eq!(params[0].0, "a"); + assert_eq!(params[0].1, Type::TInteger); + assert_eq!(params[1].0, "b"); + assert_eq!(params[1].1, Type::TInteger); + + match *lcm_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TInteger); + }, + _ => panic!("Expected MetaExp inside Return for lcm"), + } + }, + _ => panic!("Expected Return statement for lcm body"), + } + } + + #[test] + fn test_load_math_stdlib_contains_comb(){ + let math_stdlib = load_math_stdlib(); + let comb_func = math_stdlib.get("comb").expect("Function 'comb' not found in math stdlib"); + + assert_eq!(comb_func.kind, Type::TInteger); + + let params = comb_func.params.as_ref().expect("Expected parameters for comb"); + assert_eq!(params.len(), 2); + assert_eq!(params[0].0, "n"); + assert_eq!(params[0].1, Type::TInteger); + assert_eq!(params[1].0, "k"); + assert_eq!(params[1].1, Type::TInteger); + + match *comb_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TInteger); + }, + _ => panic!("Expected MetaExp inside Return for comb"), + } + }, + _ => panic!("Expected Return statement for comb body"), + } + } + + #[test] + fn test_load_math_stdlib_contains_perm(){ + let math_stdlib = load_math_stdlib(); + let perm_func = math_stdlib.get("perm").expect("Function 'perm' not found in math stdlib"); + + assert_eq!(perm_func.kind, Type::TInteger); + + let params = perm_func.params.as_ref().expect("Expected parameters for perm"); + assert_eq!(params.len(), 2); + assert_eq!(params[0].0, "n"); + assert_eq!(params[0].1, Type::TInteger); + assert_eq!(params[1].0, "k"); + assert_eq!(params[1].1, Type::TInteger); + + match *perm_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TInteger); + }, + _ => panic!("Expected MetaExp inside Return for perm"), + } + }, + _ => panic!("Expected Return statement for perm body"), + } + } + + #[test] + fn test_load_math_stdlib_contains_is_prime(){ + let math_stdlib = load_math_stdlib(); + let is_prime_func = math_stdlib.get("is_prime").expect("Function 'is_prime' not found in math stdlib"); + + assert_eq!(is_prime_func.kind, Type::TBool); + + let params = is_prime_func.params.as_ref().expect("Expected parameters for is_prime"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "x"); + assert_eq!(params[0].1, Type::TInteger); + + match *is_prime_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TBool); + }, + _ => panic!("Expected MetaExp inside Return for is_prime"), + } + }, + _ => panic!("Expected Return statement for is_prime body"), + } + } + + #[test] + fn test_load_math_stdlib_contains_log(){ + let math_stdlib = load_math_stdlib(); + let log_func = math_stdlib.get("log").expect("Function 'log' not found in math stdlib"); + + assert_eq!(log_func.kind, Type::TReal); + + let params = log_func.params.as_ref().expect("Expected parameters for log"); + assert_eq!(params.len(), 2); + assert_eq!(params[0].0, "x"); + assert_eq!(params[0].1, Type::TReal); + assert_eq!(params[1].0, "base"); + assert_eq!(params[1].1, Type::TReal); + + match *log_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TReal); + }, + _ => panic!("Expected MetaExp inside Return for log"), + } + }, + _ => panic!("Expected Return statement for log body"), + } + } + + #[test] + fn test_load_string_stdlib_contains_str_upper() { + let string_stdlib = load_string_stdlib(); + let str_upper_func = string_stdlib.get("str_upper").expect("Function 'str_upper' not found in string stdlib"); + + assert_eq!(str_upper_func.kind, Type::TString); + + let params = str_upper_func.params.as_ref().expect("Expected parameters for str_upper"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "s"); + assert_eq!(params[0].1, Type::TString); + + match *str_upper_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TString); + }, + _ => panic!("Expected MetaExp inside Return for str_upper"), + } + }, + _ => panic!("Expected Return statement for str_upper body"), + } + } + + #[test] + fn test_load_string_stdlib_contains_str_lower() { + let string_stdlib = load_string_stdlib(); + let str_lower_func = string_stdlib.get("str_lower").expect("Function 'str_lower' not found in string stdlib"); + + assert_eq!(str_lower_func.kind, Type::TString); + + let params = str_lower_func.params.as_ref().expect("Expected parameters for str_lower"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "s"); + assert_eq!(params[0].1, Type::TString); + + match *str_lower_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TString); + }, + _ => panic!("Expected MetaExp inside Return for str_lower"), + } + }, + _ => panic!("Expected Return statement for str_lower body"), + } + } + + #[test] + fn test_load_string_stdlib_contains_str_length() { + let string_stdlib = load_string_stdlib(); + let str_length_func = string_stdlib.get("str_length").expect("Function 'str_length' not found in string stdlib"); + + assert_eq!(str_length_func.kind, Type::TInteger); + + let params = str_length_func.params.as_ref().expect("Expected parameters for str_length"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "s"); + assert_eq!(params[0].1, Type::TString); + + match *str_length_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TInteger); + }, + _ => panic!("Expected MetaExp inside Return for str_length"), + } + }, + _ => panic!("Expected Return statement for str_length body"), + } + } + + #[test] + fn test_load_string_stdlib_contains_str_reverse(){ + let string_stdlib = load_string_stdlib(); + let str_reverse_func = string_stdlib.get("str_reverse").expect("Function 'str_reverse' not found in string stdlib"); + + assert_eq!(str_reverse_func.kind, Type::TString); + + let params = str_reverse_func.params.as_ref().expect("Expected parameters for str_reverse"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "s"); + assert_eq!(params[0].1, Type::TString); + + match *str_reverse_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TString); + }, + _ => panic!("Expected MetaExp inside Return for str_reverse"), + } + }, + _ => panic!("Expected Return statement for str_reverse body"), + } + } + + #[test] + fn test_load_string_stdlib_contains_cont_chars(){ + let string_stdlib = load_string_stdlib(); + let cont_chars_func = string_stdlib.get("cont_chars").expect("Function 'cont_chars' not found in string stdlib"); + + assert_eq!(cont_chars_func.kind, Type::TInteger); + + let params = cont_chars_func.params.as_ref().expect("Expected parameters for cont_chars"); + assert_eq!(params.len(), 2); + assert_eq!(params[0].0, "s"); + assert_eq!(params[0].1, Type::TString); + assert_eq!(params[1].0, "c"); + assert_eq!(params[1].1, Type::TString); + + match *cont_chars_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TInteger); + }, + _ => panic!("Expected MetaExp inside Return for cont_chars"), + } + }, + _ => panic!("Expected Return statement for cont_chars body"), + } + } + + #[test] + fn test_load_string_stdlib_contains_filter_out_char(){ + let string_stdlib = load_string_stdlib(); + let filter_out_char_func = string_stdlib.get("filter_out_char").expect("Function 'filter_out_char' not found in string stdlib"); + + assert_eq!(filter_out_char_func.kind, Type::TString); + + let params = filter_out_char_func.params.as_ref().expect("Expected parameters for filter_out_char"); + assert_eq!(params.len(), 2); + assert_eq!(params[0].0, "s"); + assert_eq!(params[0].1, Type::TString); + assert_eq!(params[1].0, "c"); + assert_eq!(params[1].1, Type::TString); + + match *filter_out_char_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TString); + }, + _ => panic!("Expected MetaExp inside Return for filter_out_char"), + } + }, + _ => panic!("Expected Return statement for filter_out_char body"), + } + } + + #[test] + fn test_load_string_stdlib_contains_replace(){ + let string_stdlib = load_string_stdlib(); + let replace_func = string_stdlib.get("replace").expect("Function 'replace' not found in string stdlib"); + + assert_eq!(replace_func.kind, Type::TString); + + let params = replace_func.params.as_ref().expect("Expected parameters for replace"); + assert_eq!(params.len(), 4); + assert_eq!(params[0].0, "s"); + assert_eq!(params[0].1, Type::TString); + assert_eq!(params[1].0, "old"); + assert_eq!(params[1].1, Type::TString); + assert_eq!(params[2].0, "new"); + assert_eq!(params[2].1, Type::TString); + assert_eq!(params[3].0, "count"); + assert_eq!(params[3].1, Type::TInteger); + + match *replace_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 4); + assert_eq!(*ret_type, Type::TString); + }, + _ => panic!("Expected MetaExp inside Return for replace"), + } + }, + _ => panic!("Expected Return statement for replace body"), + } + } +} \ No newline at end of file diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index def0ec8..eaddbc6 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -1,6 +1,126 @@ -use crate::ir::ast::{EnvValue, Expression}; +use std::collections::HashMap; +use crate::ir::ast::{Function, Type, Statement, Expression, EnvValue}; -pub fn str_upper(args: Vec) -> Result { +pub fn load_string_stdlib() -> HashMap { + let mut string_stdlib = HashMap::new(); + + string_stdlib.insert( + "str_upper".to_string(), + Function { + kind: Type::TString, + params: Some(vec![("s".to_string(), Type::TString)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + str_upper_impl, + vec![Expression::Var("s".to_string())], + Type::TString, + )))), + }, + ); + + string_stdlib.insert( + "str_lower".to_string(), + Function { + kind: Type::TString, + params: Some(vec![("s".to_string(), Type::TString)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + str_lower_impl, + vec![Expression::Var("s".to_string())], + Type::TString, + )))), + }, + ); + + string_stdlib.insert( + "str_length".to_string(), + Function { + kind: Type::TInteger, + params: Some(vec![("s".to_string(), Type::TString)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + str_length_impl, + vec![Expression::Var("s".to_string())], + Type::TInteger, + )))), + }, + ); + + string_stdlib.insert( + "str_reverse".to_string(), + Function { + kind: Type::TString, + params: Some(vec![("s".to_string(), Type::TString)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + str_reverse_impl, + vec![Expression::Var("s".to_string())], + Type::TString, + )))), + }, + ); + + string_stdlib.insert( + "cont_chars".to_string(), + Function { + kind: Type::TInteger, + params: Some(vec![ + ("s".to_string(), Type::TString), + ("c".to_string(), Type::TString), + ]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + cont_chars_impl, + vec![ + Expression::Var("s".to_string()), + Expression::Var("c".to_string()), + ], + Type::TInteger, + )))), + }, + ); + + string_stdlib.insert( + "filter_out_char".to_string(), + Function { + kind: Type::TString, + params: Some(vec![ + ("s".to_string(), Type::TString), + ("c".to_string(), Type::TString), + ]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + filter_out_char_impl, + vec![ + Expression::Var("s".to_string()), + Expression::Var("c".to_string()), + ], + Type::TString, + )))), + }, + ); + + string_stdlib.insert( + "replace".to_string(), + Function { + kind: Type::TString, + params: Some(vec![ + ("s".to_string(), Type::TString), + ("old".to_string(), Type::TString), + ("new".to_string(), Type::TString), + ("count".to_string(), Type::TInteger), + ]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + replace_impl, + vec![ + Expression::Var("s".to_string()), + Expression::Var("old".to_string()), + Expression::Var("new".to_string()), + Expression::Var("count".to_string()), + ], + Type::TString, + )))), + }, + ); + + string_stdlib +} + +pub fn str_upper_impl(args: Vec) -> Result { if args.len() != 1 { return Err("str_upper expects exactly one argument".to_string()); } @@ -12,7 +132,7 @@ pub fn str_upper(args: Vec) -> Result { } } -pub fn str_lower(args: Vec) -> Result { +pub fn str_lower_impl(args: Vec) -> Result { if args.len() != 1 { return Err("str_lower expects exactly one argument".to_string()); } @@ -23,7 +143,7 @@ pub fn str_lower(args: Vec) -> Result { } } -pub fn str_length(args: Vec) -> Result { +pub fn str_length_impl(args: Vec) -> Result { if args.len() != 1 { return Err("str_length expects exactly one argument".to_string()); } @@ -34,7 +154,7 @@ pub fn str_length(args: Vec) -> Result { } } -pub fn str_reverse(args: Vec) -> Result { +pub fn str_reverse_impl(args: Vec) -> Result { if args.len() != 1 { return Err("str_reverse expects exactly one argument".to_string()); } @@ -45,7 +165,7 @@ pub fn str_reverse(args: Vec) -> Result { } } -pub fn cont_chars(args: Vec) -> Result { +pub fn cont_chars_impl(args: Vec) -> Result { if args.len() != 2 { return Err("cont_chars expects exactly two arguments".to_string()); } @@ -60,7 +180,7 @@ pub fn cont_chars(args: Vec) -> Result { } } -pub fn filter_out_char(args: Vec) -> Result { +pub fn filter_out_char_impl(args: Vec) -> Result { if args.len() != 2 { return Err("filter_out_char expects exactly two arguments".to_string()); } @@ -75,7 +195,7 @@ pub fn filter_out_char(args: Vec) -> Result { } } -pub fn replace(args: Vec) -> Result { +pub fn replace_impl(args: Vec) -> Result { if args.len() < 3 || args.len() > 4 { return Err("replace expects between 3 and 4 arguments".to_string()); } @@ -120,7 +240,7 @@ mod tests { #[test] fn test_str_lower_valid_strings() { - let result = str_lower(vec![EnvValue::Exp(Expression::CString(String::from("HELLO")))]); + let result = str_lower_impl(vec![EnvValue::Exp(Expression::CString(String::from("HELLO")))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CString(res_value))) = result { assert_eq!(res_value, "hello"); @@ -129,7 +249,7 @@ mod tests { #[test] fn test_str_length_valid_string() { - let result = str_length(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); + let result = str_length_impl(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CInt(len))) = result { assert_eq!(len, 5); @@ -138,7 +258,7 @@ mod tests { #[test] fn test_str_reverse_valid_string() { - let result = str_reverse(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); + let result = str_reverse_impl(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CString(res_value))) = result { assert_eq!(res_value, "olleh"); @@ -147,7 +267,7 @@ mod tests { #[test] fn test_cont_chars_valid_input() { - let result = cont_chars(vec![ + let result = cont_chars_impl(vec![ EnvValue::Exp(Expression::CString(String::from("banana"))), EnvValue::Exp(Expression::CString(String::from("a"))), ]); @@ -159,7 +279,7 @@ mod tests { #[test] fn test_filter_out_char_valid_input() { - let result = filter_out_char(vec![ + let result = filter_out_char_impl(vec![ EnvValue::Exp(Expression::CString(String::from("banana"))), EnvValue::Exp(Expression::CString(String::from("a"))), ]); @@ -171,7 +291,7 @@ mod tests { #[test] fn test_replace_valid_input() { - let result = replace(vec![ + let result = replace_impl(vec![ EnvValue::Exp(Expression::CString(String::from("banana"))), EnvValue::Exp(Expression::CString(String::from("a"))), EnvValue::Exp(Expression::CString(String::from("o"))), diff --git a/src/tc/type_checker.rs b/src/tc/type_checker.rs index c85d783..fcd235a 100644 --- a/src/tc/type_checker.rs +++ b/src/tc/type_checker.rs @@ -28,7 +28,7 @@ pub fn check_exp(exp: Expression, env: &Environment) -> Result check_bin_relational_expression(*l, *r, env), Expression::Var(name) => check_var_name(name, env), Expression::FuncCall(name, args) => check_func_call(name, args, env), - Expression::MetaExp(_, args, return_type) => check_metastmt(args, return_type, env), + Expression::MetaExp(_, args, return_type) => check_metaexp(args, return_type, env), } } @@ -155,17 +155,6 @@ pub fn check_stmt( Ok(ControlType::Return(exp_type)) } - - Statement::MetaStmt(_, args, return_type) => { - for arg in args { - check_exp(arg.clone(), env)?; - } - - let mut new_env = env.clone(); - new_env.insert("metaResult".to_string(), (None, return_type.clone())); - Ok(ControlType::Continue(new_env)) - } - _ => Err(String::from("not implemented yet")), } } @@ -270,7 +259,7 @@ fn check_bin_relational_expression( } } -fn check_metastmt( +fn check_metaexp( args: Vec, return_type: Type, env: &Environment, @@ -291,8 +280,8 @@ mod tests { use crate::ir::ast::Function; use crate::ir::ast::Statement::*; use crate::ir::ast::Type::*; - use crate::stdlib::math::sqrt; - + use crate::stdlib::math::sqrt_impl; + #[test] fn check_tlist_comparison() { let t_list1 = TList(Box::new(TInteger)); @@ -809,96 +798,20 @@ mod tests { } #[test] - fn check_metastmt_valid() { - let mut env = Environment::new(); - env.insert( - "x".to_string(), - ( - Some(EnvValue::Exp(Expression::CReal(9.0))), - Type::TReal, - ), - ); - - let meta_stmt = Statement::MetaStmt( - sqrt, - vec![Expression::Var("x".to_string())], - Type::TReal, - ); - - let assign_stmt = Statement::Assignment( - "result".to_string(), - Box::new(Expression::Var("metaResult".to_string())), - Some(Type::TReal), - ); - - let program = Statement::Sequence( - Box::new(meta_stmt), - Box::new(assign_stmt), - ); - - match check_stmt(program, &env, None) { - Ok(ControlType::Continue(new_env)) => { - let meta_result_type = new_env - .get("metaResult") - .expect("metaResult was not found in the environment") - .1 - .clone(); - assert_eq!(meta_result_type, Type::TReal); - } - Ok(_) => panic!("Type checker should have returned a new environment"), - Err(err) => panic!("Type checker should not have failed: {}", err), - } - } - - #[test] - fn check_metastmt_invalid_assignment() { - let mut env = Environment::new(); - env.insert( - "x".to_string(), - ( - Some(EnvValue::Exp(Expression::CReal(16.0))), - Type::TReal, - ), - ); - - let meta_stmt = Statement::MetaStmt( - sqrt, - vec![Expression::Var("x".to_string())], - Type::TReal, - ); - - let assign_stmt = Statement::Assignment( - "result".to_string(), - Box::new(Expression::Var("metaResult".to_string())), - Some(Type::TBool), - ); - - let program = Statement::Sequence( - Box::new(meta_stmt), - Box::new(assign_stmt), - ); - - match check_stmt(program, &env, None) { - Err(_err) => (), - Ok(_) => panic!("Type checker should have failed"), - } - } - - #[test] - fn check_metaexp_sqrt_correct() { - let mut env = Environment::new(); + fn check_metaexp_sqrt_impl() { + let mut env = HashMap::new(); env.insert( "x".to_string(), (Some(EnvValue::Exp(Expression::CReal(25.0))), Type::TReal), ); let meta_expr = Expression::MetaExp( - sqrt, + sqrt_impl, vec![Expression::Var("x".to_string())], Type::TReal, ); - let ty = check_exp(meta_expr, &env).unwrap(); + let ty = check_exp(meta_expr, &env).expect("Type checking failed"); assert_eq!(ty, Type::TReal); } } From 83136028a88d90eff6d7a8512eecbce999421a4e Mon Sep 17 00:00:00 2001 From: Layr Neto Date: Thu, 20 Feb 2025 21:47:21 -0300 Subject: [PATCH 13/15] =?UTF-8?q?Adi=C3=A7=C3=A3o=20fun=C3=A7=C3=B5es=20tr?= =?UTF-8?q?igonom=C3=A9tricas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stdlib/math.rs | 231 +++++++++++++++++++++++++++++++++++++++++++ src/stdlib/stdlib.rs | 131 +++++++++++++++++++++++- 2 files changed, 361 insertions(+), 1 deletion(-) diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs index 0e2d379..04329f4 100644 --- a/src/stdlib/math.rs +++ b/src/stdlib/math.rs @@ -77,6 +77,51 @@ pub fn load_math_stdlib() -> HashMap { } ); + math_stdlib.insert( + "degrees".to_string(), + Function { + kind: Type::TReal, + params: Some(vec![("rad".to_string(), Type::TReal)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(degrees_impl, vec![Expression::Var("rad".to_string())], Type::TReal)))) + } + ); + + math_stdlib.insert( + "radians".to_string(), + Function { + kind: Type::TReal, + params: Some(vec![("deg".to_string(), Type::TReal)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(radians_impl, vec![Expression::Var("deg".to_string())], Type::TReal)))) + } + ); + + math_stdlib.insert( + "cos".to_string(), + Function { + kind: Type::TReal, + params: Some(vec![("x".to_string(), Type::TReal)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(cos_impl, vec![Expression::Var("x".to_string())], Type::TReal)))) + } + ); + + math_stdlib.insert( + "sin".to_string(), + Function { + kind: Type::TReal, + params: Some(vec![("x".to_string(), Type::TReal)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(sin_impl, vec![Expression::Var("x".to_string())], Type::TReal)))) + } + ); + + math_stdlib.insert( + "tan".to_string(), + Function { + kind: Type::TReal, + params: Some(vec![("x".to_string(), Type::TReal)]), + body: Box::new(Statement::Return(Box::new(Expression::MetaExp(tan_impl, vec![Expression::Var("x".to_string())], Type::TReal)))) + } + ); + math_stdlib } @@ -256,6 +301,116 @@ pub fn log_impl(args: Vec) -> Result { } } +// Constante de PI com precisão suficiente +const PI: f64 = 3.141592653589793; +const EPSILON: f64 = 1e-10; + +// Função para calcular o fatorial (usada em série de Taylor) +fn factorial(n: i32) -> f64 { + (1..=n).fold(1, |acc, x| acc * x) as f64 +} + +// Função para converter radianos em graus +pub fn degrees_impl(args: Vec) -> Result { + if args.len() != 1 { + return Err("degrees expects exactly one argument".to_string()); + } + + if let EnvValue::Exp(Expression::CReal(rad)) = &args[0] { + Ok(EnvValue::Exp(Expression::CReal(rad * (180.0 / PI)))) + } else { + Err("degrees expects a real number argument".to_string()) + } +} + +// Função para converter graus em radianos +pub fn radians_impl(args: Vec) -> Result { + if args.len() != 1 { + return Err("radians expects exactly one argument".to_string()); + } + + if let EnvValue::Exp(Expression::CReal(deg)) = &args[0] { + Ok(EnvValue::Exp(Expression::CReal(deg * (PI / 180.0)))) + } else { + Err("radians expects a real number argument".to_string()) + } +} + +// Série de Taylor para cosseno +fn taylor_cos(x: f64) -> f64 { + let mut sum = 0.0; + let mut term; + let mut n = 0; + loop { + term = ((-1.0f64).powi(n) * x.powi(2 * n)) / factorial(2 * n); + sum += term; + if term.abs() < EPSILON { + break; + } + n += 1; + } + sum +} + +// Série de Taylor para seno +fn taylor_sin(x: f64) -> f64 { + let mut sum = 0.0; + let mut term; + let mut n = 0; + loop { + term = ((-1.0f64).powi(n) * x.powi(2 * n + 1)) / factorial(2 * n + 1); + sum += term; + if term.abs() < EPSILON { + break; + } + n += 1; + } + sum +} + +// Tangente usando seno e cosseno +fn taylor_tan(x: f64) -> f64 { + taylor_sin(x) / taylor_cos(x) +} + +// Função cosseno +pub fn cos_impl(args: Vec) -> Result { + if args.len() != 1 { + return Err("cos expects exactly one argument".to_string()); + } + + if let EnvValue::Exp(Expression::CReal(x)) = &args[0] { + Ok(EnvValue::Exp(Expression::CReal(taylor_cos(*x)))) + } else { + Err("cos expects a real number argument".to_string()) + } +} + +// Função seno +pub fn sin_impl(args: Vec) -> Result { + if args.len() != 1 { + return Err("sin expects exactly one argument".to_string()); + } + + if let EnvValue::Exp(Expression::CReal(x)) = &args[0] { + Ok(EnvValue::Exp(Expression::CReal(taylor_sin(*x)))) + } else { + Err("sin expects a real number argument".to_string()) + } +} + +// Função tangente +pub fn tan_impl(args: Vec) -> Result { + if args.len() != 1 { + return Err("tan expects exactly one argument".to_string()); + } + + if let EnvValue::Exp(Expression::CReal(x)) = &args[0] { + Ok(EnvValue::Exp(Expression::CReal(taylor_tan(*x)))) + } else { + Err("tan expects a real number argument".to_string()) + } +} #[cfg(test)] mod tests { @@ -769,4 +924,80 @@ mod tests { assert!(result.is_err()); assert_eq!(result.unwrap_err(), "log expects two real arguments"); } + #[test] +fn test_degrees_impl() { + let arg = vec![EnvValue::Exp(Expression::CReal(PI))]; + let result = degrees_impl(arg).unwrap(); + if let EnvValue::Exp(Expression::CReal(deg)) = result { + assert!((deg - 180.0).abs() < EPSILON); + } else { + panic!("Unexpected result type"); + } +} + +#[test] +fn test_radians_impl() { + let arg = vec![EnvValue::Exp(Expression::CReal(180.0))]; + let result = radians_impl(arg).unwrap(); + if let EnvValue::Exp(Expression::CReal(rad)) = result { + assert!((rad - PI).abs() < EPSILON); + } else { + panic!("Unexpected result type"); + } +} + +#[test] +fn test_cos_impl() { + let arg = vec![EnvValue::Exp(Expression::CReal(0.0))]; + let result = cos_impl(arg).unwrap(); + if let EnvValue::Exp(Expression::CReal(value)) = result { + assert!((value - 1.0).abs() < EPSILON); + } else { + panic!("Unexpected result type"); + } +} + +#[test] +fn test_sin_impl() { + let arg = vec![EnvValue::Exp(Expression::CReal(0.0))]; + let result = sin_impl(arg).unwrap(); + if let EnvValue::Exp(Expression::CReal(value)) = result { + assert!(value.abs() < EPSILON); + } else { + panic!("Unexpected result type"); + } +} + +#[test] +fn test_tan_impl() { + let arg = vec![EnvValue::Exp(Expression::CReal(0.0))]; + let result = tan_impl(arg).unwrap(); + if let EnvValue::Exp(Expression::CReal(value)) = result { + assert!(value.abs() < EPSILON); + } else { + panic!("Unexpected result type"); + } +} + +#[test] +fn test_invalid_args() { + // Teste com número errado de argumentos + let too_many_args = vec![ + EnvValue::Exp(Expression::CReal(1.0)), + EnvValue::Exp(Expression::CReal(2.0)) + ]; + assert!(degrees_impl(too_many_args.clone()).is_err()); + assert!(radians_impl(too_many_args.clone()).is_err()); + assert!(cos_impl(too_many_args.clone()).is_err()); + assert!(sin_impl(too_many_args.clone()).is_err()); + assert!(tan_impl(too_many_args.clone()).is_err()); + + // Teste com tipo errado de argumento + let invalid_type_arg = vec![EnvValue::Exp(Expression::CString("invalid".to_string()))]; + assert!(degrees_impl(invalid_type_arg.clone()).is_err()); + assert!(radians_impl(invalid_type_arg.clone()).is_err()); + assert!(cos_impl(invalid_type_arg.clone()).is_err()); + assert!(sin_impl(invalid_type_arg.clone()).is_err()); + assert!(tan_impl(invalid_type_arg.clone()).is_err()); +} } \ No newline at end of file diff --git a/src/stdlib/stdlib.rs b/src/stdlib/stdlib.rs index d7688d1..1319d63 100644 --- a/src/stdlib/stdlib.rs +++ b/src/stdlib/stdlib.rs @@ -244,6 +244,58 @@ mod stdlib_tests { } } + #[test] + fn test_load_math_stdlib_contains_degrees(){ + let math_stdlib = load_math_stdlib(); + let degrees_func = math_stdlib.get("degrees").expect("Function 'degrees' not found in math stdlib"); + + assert_eq!(degrees_func.kind, Type::TReal); + + let params = degrees_func.params.as_ref().expect("Expected parameters for degrees"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "rad"); + assert_eq!(params[0].1, Type::TReal); + + match *degrees_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); + }, + _ => panic!("Expected MetaExp inside Return for degrees"), + } + }, + _ => panic!("Expected Return statement for degrees body"), + } + } + + #[test] + fn test_load_math_stdlib_contains_radians(){ + let math_stdlib = load_math_stdlib(); + let radians_func = math_stdlib.get("radians").expect("Function 'radians' not found in math stdlib"); + + assert_eq!(radians_func.kind, Type::TReal); + + let params = radians_func.params.as_ref().expect("Expected parameters for radians"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "deg"); + assert_eq!(params[0].1, Type::TReal); + + match *radians_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); + }, + _ => panic!("Expected MetaExp inside Return for radians"), + } + }, + _ => panic!("Expected Return statement for radians body"), + } + } + #[test] fn test_load_string_stdlib_contains_str_upper() { let string_stdlib = load_string_stdlib(); @@ -270,6 +322,84 @@ mod stdlib_tests { } } + #[test] + fn test_load_math_stdlib_contains_cos(){ + let math_stdlib = load_math_stdlib(); + let cos_func = math_stdlib.get("cos").expect("Function 'cos' not found in math stdlib"); + + assert_eq!(cos_func.kind, Type::TReal); + + let params = cos_func.params.as_ref().expect("Expected parameters for cos"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "x"); + assert_eq!(params[0].1, Type::TReal); + + match *cos_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); + }, + _ => panic!("Expected MetaExp inside Return for cos"), + } + }, + _ => panic!("Expected Return statement for cos body"), + } + } + + #[test] + fn test_load_math_stdlib_contains_sin(){ + let math_stdlib = load_math_stdlib(); + let sin_func = math_stdlib.get("sin").expect("Function 'sin' not found in math stdlib"); + + assert_eq!(sin_func.kind, Type::TReal); + + let params = sin_func.params.as_ref().expect("Expected parameters for sin"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "x"); + assert_eq!(params[0].1, Type::TReal); + + match *sin_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); + }, + _ => panic!("Expected MetaExp inside Return for sin"), + } + }, + _ => panic!("Expected Return statement for sin body"), + } + } + + #[test] + fn test_load_math_stdlib_contains_tan(){ + let math_stdlib = load_math_stdlib(); + let tan_func = math_stdlib.get("tan").expect("Function 'tan' not found in math stdlib"); + + assert_eq!(tan_func.kind, Type::TReal); + + let params = tan_func.params.as_ref().expect("Expected parameters for tan"); + assert_eq!(params.len(), 1); + assert_eq!(params[0].0, "x"); + assert_eq!(params[0].1, Type::TReal); + + match *tan_func.body { + Statement::Return(ref inner) => { + match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); + }, + _ => panic!("Expected MetaExp inside Return for tan"), + } + }, + _ => panic!("Expected Return statement for tan body"), + } + } + #[test] fn test_load_string_stdlib_contains_str_lower() { let string_stdlib = load_string_stdlib(); @@ -295,7 +425,6 @@ mod stdlib_tests { _ => panic!("Expected Return statement for str_lower body"), } } - #[test] fn test_load_string_stdlib_contains_str_length() { let string_stdlib = load_string_stdlib(); From 69edce05ff3b58f4eb02a88c891a4019ff44c522 Mon Sep 17 00:00:00 2001 From: Layr Neto Date: Tue, 25 Feb 2025 17:32:55 -0300 Subject: [PATCH 14/15] =?UTF-8?q?Integra=C3=A7=C3=A3o=20do=20Meta=20com=20?= =?UTF-8?q?Environment=20e=20Frame?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/interpreter/interpreter.rs | 1255 +++++++++++++++++++++++++++++--- src/ir/ast.rs | 87 ++- src/main.rs | 340 ++++++++- src/parser/parser.rs | 486 ++++++++++++- src/stdlib/math.rs | 69 +- src/stdlib/stdlib.rs | 82 +-- src/stdlib/string.rs | 52 +- src/tc/type_checker.rs | 245 ++++++- 8 files changed, 2392 insertions(+), 224 deletions(-) diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index cd8fa82..ac416f7 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -1,16 +1,16 @@ -use crate::ir::ast::{Environment, Expression, Function, Name, Statement, Type, Type}; // Fixed imports -use crate::tc::type_checker::check_stmt; -use crate::HashMap; +use std::collections::HashSet; -type ErrorMessage = String; +use crate::ir::ast::{Environment, Expression, Function, Name, Statement, TestEnvironment}; + +type ErrorMessage = (String, Option); #[derive(Clone, Debug, PartialEq)] pub enum EnvValue { Exp(Expression), Func(Function), + TestEnvironment(TestEnvironment), } -#[derive(Debug)] pub enum ControlFlow { Continue(Environment), Return(EnvValue), @@ -31,59 +31,61 @@ pub fn eval(exp: Expression, env: &Environment) -> Result gte(*lhs, *rhs, env), Expression::LTE(lhs, rhs) => lte(*lhs, *rhs, env), Expression::Var(name) => lookup(name, env), + Expression::COk(e) => eval_ok(*e, env), + Expression::CErr(e) => eval_err(*e, env), + Expression::CJust(e) => eval_just(*e, env), + Expression::Unwrap(e) => eval_unwrap_expression(*e, env), + Expression::Propagate(e) => eval_propagate_expression(*e, env), + Expression::IsError(e) => eval_iserror_expression(*e, env), + Expression::IsNothing(e) => eval_isnothing_expression(*e, env), Expression::FuncCall(name, args) => call(name, args, env), - Expression::MetaExp(f, args, return_type) => meta(f, args, return_type, env), + Expression::MetaExp(f, args, _) => meta(f, args, env), _ if is_constant(exp.clone()) => Ok(EnvValue::Exp(exp)), - _ => Err(String::from("Not implemented yet.")), + _ => Err((String::from("Not implemented yet."), None)), } } -// Helper function for executing blocks -fn execute_block( - stmts: Vec, - env: &Environment, -) -> Result { - let mut current_env = env.clone(); - - for stmt in stmts { - match execute(stmt, ¤t_env)? { - ControlFlow::Continue(new_env) => current_env = new_env, - ControlFlow::Return(value) => return Ok(ControlFlow::Return(value)), - } +pub fn run(stmt: Statement, env: &Environment) -> Result { + match execute(stmt, env) { + Ok(e) => Ok(e), + Err((s, _)) => Err(s), } - - Ok(ControlFlow::Continue(current_env)) } -pub fn execute(stmt: Statement, env: &Environment) -> Result { +fn execute(stmt: Statement, env: &Environment) -> Result { let mut new_env = env.clone(); - match stmt { + let result = match stmt { Statement::Assignment(name, exp, _) => { let value = eval(*exp, &new_env)?; new_env.insert_variable(name, value); // Remove the tuple Ok(ControlFlow::Continue(new_env)) } - Statement::IfThenElse(cond, then_stmt, else_stmt) => { + + Statement::IfThenElse(cond, stmt_then, stmt_else) => { let value = eval(*cond, &new_env)?; + match value { - EnvValue::Exp(Expression::CTrue) => match *then_stmt { + EnvValue::Exp(Expression::CTrue) => match *stmt_then { Statement::Block(stmts) => execute_block(stmts, &new_env), - _ => execute(*then_stmt, &new_env), + _ => execute(*stmt_then, &new_env), }, - EnvValue::Exp(Expression::CFalse) => match else_stmt { + EnvValue::Exp(Expression::CFalse) => match stmt_else { Some(else_stmt) => match *else_stmt { Statement::Block(stmts) => execute_block(stmts, &new_env), _ => execute(*else_stmt, &new_env), }, None => Ok(ControlFlow::Continue(new_env)), }, - _ => Err("Condition must evaluate to a boolean".to_string()), + _ => Err(("Condition must evaluate to a boolean".to_string(), None)), } } + Statement::Block(stmts) => execute_block(stmts, &new_env), + Statement::While(cond, stmt) => { let mut value = eval(*cond.clone(), &new_env)?; + loop { match value { EnvValue::Exp(Expression::CTrue) => match execute(*stmt.clone(), &new_env)? { @@ -98,6 +100,91 @@ pub fn execute(stmt: Statement, env: &Environment) -> Result { + let value = eval(*cond, &env)?; + match value { + EnvValue::Exp(Expression::CTrue) => Ok(ControlFlow::Continue(env.clone())), + EnvValue::Exp(Expression::CFalse) => Err((error, None)), + _ => Err((String::from("expecting a boolean value."), None)), + } + } + + Statement::AssertFalse(cond, error) => { + let value = eval(*cond, &env)?; + match value { + EnvValue::Exp(Expression::CFalse) => Ok(ControlFlow::Continue(env.clone())), + EnvValue::Exp(Expression::CTrue) => Err((error, None)), + _ => Err((String::from("expecting a boolean value."), None)), + } + } + + Statement::AssertEQ(value1, value2, error) => { + match execute( + Statement::AssertTrue( + Box::new(match eq(*value1, *value2, &env)? { + EnvValue::Exp(Expression::CTrue) => Expression::CTrue, + EnvValue::Exp(Expression::CFalse) => Expression::CFalse, + _ => return Err((String::from(""), None)), + }), + error, + ), + env, + ) { + Ok(ControlFlow::Continue(new_env)) => Ok(ControlFlow::Continue(new_env)), + Err(err) => Err(err), + _ => Err((String::from("arguments are not of the same type"), None)), + } + } + + Statement::AssertNEQ(value1, value2, error) => { + match execute( + Statement::AssertFalse( + Box::new(match eq(*value1, *value2, &env)? { + EnvValue::Exp(Expression::CTrue) => Expression::CTrue, + EnvValue::Exp(Expression::CFalse) => Expression::CFalse, + _ => return Err((String::from(""), None)), + }), + error, + ), + env, + ) { + Ok(ControlFlow::Continue(new_env)) => Ok(ControlFlow::Continue(new_env)), + Err(err) => Err(err), + _ => Err((String::from("arguments are not of the same type"), None)), + } + } + + Statement::AssertFails(error) => Err((error, None)), + + Statement::TestDef(mut test) => { + test.body = Some(Box::new(Statement::Sequence( + test.body.unwrap(), + Box::new(Statement::Return(Box::new(Expression::CVoid))), + ))); + + new_env.insert_test(test.name.clone(), test); + Ok(ControlFlow::Continue(new_env)) + } + + Statement::ModTestDef(name, stmt) => { + let mut mod_test: TestEnvironment = TestEnvironment::new(); + + let new_mod_test_env; + + mod_test.env = new_env.clone(); + + match execute(*stmt, &mod_test.env) { + Ok(ControlFlow::Continue(new_env)) => new_mod_test_env = new_env, + Ok(ControlFlow::Return(value)) => return Ok(ControlFlow::Return(value)), + Err(e) => return Err(e), + } + + mod_test.env = new_mod_test_env; + + new_env.insert_variable(name, EnvValue::TestEnvironment(mod_test)); + + Ok(ControlFlow::Continue(new_env)) + } Statement::Sequence(s1, s2) => match execute(*s1, &new_env)? { ControlFlow::Continue(control_env) => { new_env = control_env; @@ -109,13 +196,40 @@ pub fn execute(stmt: Statement, env: &Environment) -> Result { - let value = eval(*exp, &new_env)?; - Ok(ControlFlow::Return(value)) + let exp_value = eval(*exp, &new_env)?; + Ok(ControlFlow::Return(exp_value)) + } + _ => Err((String::from("not implemented yet"), None)), + }; + + match result { + Ok(v) => Ok(v), + Err((s, opt)) => { + if s != "Propagate".to_string() { + return Err((s, None)); + } else { + return propagate_error(opt.unwrap(), env); + } } + } +} - _ => Err(String::from("not implemented yet")), +//helper function for executing blocks +fn execute_block( + stmts: Vec, + env: &Environment, +) -> Result { + let mut current_env = env.clone(); + + for stmt in stmts { + match execute(stmt, ¤t_env)? { + ControlFlow::Continue(new_env) => current_env = new_env, + ControlFlow::Return(value) => return Ok(ControlFlow::Return(value)), + } } + Ok(ControlFlow::Continue(current_env)) } fn call( @@ -154,20 +268,164 @@ fn call( // Execute function match execute(*func.body.as_ref().unwrap().clone(), &new_env)? { ControlFlow::Return(value) => Ok(value), - ControlFlow::Continue(_) => Err("Function did not return a value".to_string()), + ControlFlow::Continue(_) => { + Err(("Function did not return a value".to_string(), None)) + } } } - _ => Err(format!("Function {} not found", name)), + _ => Err((format!("Function {} not found", name), None)), + } +} + +/* Error propagation functions: + -> extract_error_value + -> propagate_error +*/ +fn extract_error_value( + exp: Expression, + env: &Environment, +) -> Result { + // Gets expression and returns the value inside (works with constants and Error types) + match exp { + Expression::COk(e) => extract_error_value(*e, env), + Expression::CErr(e) => extract_error_value(*e, env), + Expression::CJust(e) => extract_error_value(*e, env), + Expression::CTrue => Ok("True".to_string()), + Expression::CFalse => Ok("False".to_string()), + Expression::CInt(value) => Ok(value.to_string()), + Expression::CReal(value) => Ok(value.to_string()), + Expression::CString(value) => Ok(value.to_string()), + Expression::CNothing => Ok("Nothing".to_string()), + _ => Err((String::from("Nothing to extract from."), None)), + } +} + +fn propagate_error( + exp: Expression, + env: &Environment, +) -> Result { + // Checks error value and propagates it (terminates code if on highest level function) + if env.scope_key().1 == 0 { + match eval(exp, &env) { + Ok(EnvValue::Exp(new_value)) => match extract_error_value(new_value, &env) { + Ok(s) => Err(( + String::from(format!("Program terminated with errors: {}", s)), + None, + )), + _ => Err(("Program terminated with errors".to_string(), None)), + }, + _ => Err(( + "Program panicked and trying to terminate with errors".to_string(), + None, + )), + } + } else { + return Ok(ControlFlow::Return(EnvValue::Exp(Expression::CErr( + Box::new(exp), + )))); } } +fn execute_tests( + tests_set: Vec<(String, Option)>, + env: &Environment, +) -> Result)>, String> { + let mut results = HashSet::new(); + let cur_scope = env.scope_key(); + let frame: crate::ir::ast::Frame = env.get_frame(cur_scope.clone()).clone(); + + for (mod_test, test) in tests_set { + match frame.variables.get(&mod_test) { + Some(EnvValue::TestEnvironment(test_module)) => { + let mut test_env = test_module.env.clone(); + let mod_test_scope = test_env.scope_key(); + let test_frame = test_env.get_frame(mod_test_scope); + + if test != None { + test_env = match run( + Statement::FuncDef( + match test_frame.clone().tests.get(&test.clone().unwrap()) { + Some(real_test) => real_test.clone(), + None => { + return Err(format!( + "{teste} is not a test", + teste = &test.clone().unwrap() + )) + } + }, + ), + &test_env, + ) { + Ok(ControlFlow::Continue(new_env)) => new_env, + Err(e) => return Err(e), + Ok(ControlFlow::Return(_)) => return Ok(results), + }; + + let result = match eval( + Expression::FuncCall(test.clone().unwrap(), Vec::::new()), + &test_env, + ) { + Ok(_) => ("Passou".to_string(), None), + Err((e, _)) => ("Falhou".to_string(), Some(format!("Erro: {}", e))), + }; + + results.insert(( + format!( + "{modulo}::{teste}", + teste = test.clone().unwrap(), + modulo = mod_test.clone() + ), + result.0, + result.1, + )); + continue; + } + + for (test, real_test) in test_frame.clone().tests.into_iter() { + test_env = match run(Statement::FuncDef(real_test), &test_env) { + Ok(ControlFlow::Continue(new_env)) => new_env, + Err(e) => return Err(e), + Ok(ControlFlow::Return(_)) => return Ok(results), + }; + + let result = match eval( + Expression::FuncCall(test.clone(), Vec::::new()), + &test_env, + ) { + Ok(_) => ("Passou".to_string(), None), + Err((e, _)) => ("Falhou".to_string(), Some(format!("Erro: {}", e))), + }; + + results.insert(( + format!( + "{modulo}::{teste}", + teste = test.clone(), + modulo = mod_test.clone() + ), + result.0, + result.1, + )); + } + } + _ => { + return Err(format!( + "{modulo} is not a ModTest", + modulo = mod_test.clone() + )) + } + } + } + Ok(results) +} fn is_constant(exp: Expression) -> bool { match exp { Expression::CTrue => true, Expression::CFalse => true, + Expression::CVoid => true, Expression::CInt(_) => true, Expression::CReal(_) => true, Expression::CString(_) => true, + Expression::CNothing => true, _ => false, } } @@ -198,6 +456,7 @@ where { let v1 = eval(lhs, env)?; let v2 = eval(rhs, env)?; + //// checar aqui se o status de erro é vdd, se for, retornar o valor de erro "Ok(EnvValue::Exp(Cerr q tem no env))" --> fzr teste match (v1, v2) { (EnvValue::Exp(Expression::CInt(v1)), EnvValue::Exp(Expression::CInt(v2))) => Ok( EnvValue::Exp(Expression::CInt(op(v1 as f64, v2 as f64) as i32)), @@ -211,7 +470,7 @@ where (EnvValue::Exp(Expression::CReal(v1)), EnvValue::Exp(Expression::CReal(v2))) => { Ok(EnvValue::Exp(Expression::CReal(op(v1, v2)))) } - _ => Err(error_msg.to_string()), + _ => Err((error_msg.to_string(), None)), } } @@ -284,6 +543,7 @@ where { let v1 = eval(lhs, env)?; let v2 = eval(rhs, env)?; + //// checar aqui se o status de erro é vdd, se for, retornar o valor de erro "Ok(EnvValue::Exp(Cerr q tem no env))" --> fzr teste match (v1, v2) { (EnvValue::Exp(Expression::CTrue), EnvValue::Exp(Expression::CTrue)) => { Ok(EnvValue::Exp(op(true, true))) @@ -297,7 +557,7 @@ where (EnvValue::Exp(Expression::CFalse), EnvValue::Exp(Expression::CFalse)) => { Ok(EnvValue::Exp(op(false, false))) } - _ => Err(error_msg.to_string()), + _ => Err((error_msg.to_string(), None)), } } @@ -346,7 +606,7 @@ fn not(lhs: Expression, env: &Environment) -> Result Ok(EnvValue::Exp(Expression::CFalse)), EnvValue::Exp(Expression::CFalse) => Ok(EnvValue::Exp(Expression::CTrue)), - _ => Err(String::from("'not' is only defined for booleans.")), + _ => Err((String::from("'not' is only defined for booleans."), None)), } } @@ -363,6 +623,7 @@ where { let v1 = eval(lhs, env)?; let v2 = eval(rhs, env)?; + //// checar aqui se o status de erro é vdd, se for, retornar o valor de erro "Ok(EnvValue::Exp(Cerr q tem no env))" --> fzr teste match (v1, v2) { (EnvValue::Exp(Expression::CInt(v1)), EnvValue::Exp(Expression::CInt(v2))) => { Ok(EnvValue::Exp(op(v1 as f64, v2 as f64))) @@ -376,7 +637,7 @@ where (EnvValue::Exp(Expression::CReal(v1)), EnvValue::Exp(Expression::CReal(v2))) => { Ok(EnvValue::Exp(op(v1, v2))) } - _ => Err(error_msg.to_string()), + _ => Err((error_msg.to_string(), None)), } } @@ -480,51 +741,114 @@ fn lte( ) } -fn meta( - f: fn(Vec) -> Result, - args: Vec, - return_type: Type, - env: &Environment, +fn eval_unwrap_expression( + exp: Expression, + env: &Environment, ) -> Result { + ////QUATRO/ FAz uteste também + let v = eval(exp, env)?; + match v { + EnvValue::Exp(Expression::CJust(e)) => Ok(EnvValue::Exp(*e)), + EnvValue::Exp(Expression::COk(e)) => Ok(EnvValue::Exp(*e)), + _ => Err((String::from("Program panicked trying to unwrap."), None)), + } +} - let mut args_values = Vec::new(); - for expr in &args { - let env_value = eval(expr.clone(), env)?; - args_values.push(env_value); +fn eval_propagate_expression( + exp: Expression, + env: &Environment, +) -> Result { + ////QUATRO Fazer teste com recursão pls :D + let v = eval(exp, env)?; + //let mut *new_env = env.clone(); + match v { + EnvValue::Exp(Expression::CJust(e)) => Ok(EnvValue::Exp(*e)), + EnvValue::Exp(Expression::COk(e)) => Ok(EnvValue::Exp(*e)), + EnvValue::Exp(Expression::CErr(e)) => Err(("Propagate".to_string(), Some(*e))), + EnvValue::Exp(Expression::CNothing) => Err(( + "Propagate".to_string(), + Some(Expression::CString("Couldn't unwrap Nothing".to_string())), + )), + _ => Err((String::from("'propagate' is expects a Just or Ok."), None)), } +} - let result_value = f(args_values)?; +fn eval_isnothing_expression( + exp: Expression, + env: &Environment, +) -> Result { + let v = eval(exp, env)?; + match v { + EnvValue::Exp(Expression::CNothing) => Ok(EnvValue::Exp(Expression::CTrue)), + _ => Ok(EnvValue::Exp(Expression::CFalse)), + //EnvValue::Exp(Expression::CJust(_)) => Ok(EnvValue::Exp(Expression::CFalse)), + //_ => Err("Expression not recognized.".to_string()), + } +} - if get_type_env_value(&result_value) != return_type { - return Err(format!( - "Tipo incorreto: esperado {:?}, mas a função retornou {:?}", - return_type.clone(), - get_type_env_value(&result_value) - )); - } - Ok(result_value) +fn eval_iserror_expression( + exp: Expression, + env: &Environment, +) -> Result { + let v = eval(exp, env)?; + match v { + EnvValue::Exp(Expression::CErr(_)) => Ok(EnvValue::Exp(Expression::CTrue)), + _ => Ok(EnvValue::Exp(Expression::CFalse)), + //EnvValue::Exp(Expression::COk(_)) => Ok(EnvValue::Exp(Expression::CFalse)), + //_ => Err(String::from("'is_error' is only defined for Ok and Err.")), + } +} + +fn eval_just(exp: Expression, env: &Environment) -> Result { + let v = eval(exp, env)?; + match v { + EnvValue::Exp(e) => Ok(EnvValue::Exp(Expression::CJust(Box::new(e)))), + _ => Err(("Expression not recognized.".to_string(), None)), + } +} + +fn eval_ok(exp: Expression, env: &Environment) -> Result { + let v = eval(exp, env)?; + match v { + EnvValue::Exp(e) => Ok(EnvValue::Exp(Expression::COk(Box::new(e)))), + _ => Err(("Expression not recognized.".to_string(), None)), + } } -pub fn get_type_env_value(value: &EnvValue) -> Type { - match value { - EnvValue::Exp(Expression::CInt(_)) => Type::TInteger, - EnvValue::Exp(Expression::CReal(_)) => Type::TReal, - EnvValue::Exp(Expression::CString(_)) => Type::TString, - EnvValue::Exp(Expression::CTrue) | EnvValue::Exp(Expression::CFalse) => Type::TBool, - EnvValue::Func(_) => Type::TFunction, - _ => unreachable!(), +fn eval_err(exp: Expression, env: &Environment) -> Result { + let v = eval(exp, env)?; + match v { + EnvValue::Exp(e) => Ok(EnvValue::Exp(Expression::CErr(Box::new(e)))), + _ => Err(("Expression not recognized.".to_string(), None)), } } +fn meta( + f: fn(Vec) -> Result, + args: Vec, + env: &Environment, +) -> Result)> { + let mut args_values = Vec::new(); + for expr in args { + let value = eval(expr, env)?; + args_values.push(value); + } + let result_value = f(args_values).map_err(|s| (s, None))?; + + Ok(result_value) +} + #[cfg(test)] mod tests { use super::*; use crate::ir::ast::Expression::*; use crate::ir::ast::Function; use crate::ir::ast::Statement::*; - use crate::ir::ast::Type::*; + use crate::ir::ast::Type; use crate::stdlib::math::sqrt_impl; - + use std::collections::HashMap; + //use crate::ir::ast::Type; + use crate::ir::ast::Type::*; use approx::relative_eq; #[test] @@ -538,6 +862,114 @@ mod tests { assert_eq!(eval(c20, &env), Ok(EnvValue::Exp(CInt(20)))); } + #[test] + fn eval_unwrap_result_ok() { + let env: Environment = Environment::new(); + let c10 = CInt(10); + let ok = COk(Box::new(c10)); + let u = Unwrap(Box::new(ok)); + + assert_eq!(eval(u, &env), Ok(EnvValue::Exp(CInt(10)))); + } + + #[test] + fn eval_unwrap_result_err() { + let env: Environment = Environment::new(); + let c1 = CInt(1); + let err = CErr(Box::new(c1)); + let u = Unwrap(Box::new(err)); + + match eval(u, &env) { + Err(_) => assert!(true), + _ => assert!(false, "The program was suposed to terminate"), + } + } + + #[test] + fn eval_unwrap_just() { + let env: Environment = Environment::new(); + let c5 = CInt(5); + let maybe = CJust(Box::new(c5)); + let u = Unwrap(Box::new(maybe)); + + assert_eq!(eval(u, &env), Ok(EnvValue::Exp(CInt(5)))); + } + + #[test] + fn eval_unwrap_nothing() { + let env: Environment = Environment::new(); + let u = Unwrap(Box::new(CNothing)); + + match eval(u, &env) { + Err(_) => assert!(true), + _ => assert!(false, "The program was suposed to terminate"), + } + } + + #[test] + fn eval_is_error_result_true() { + let env: Environment = Environment::new(); + let aux = CInt(2); + let e = Expression::CErr(Box::new(aux)); + let ie = IsError(Box::new(e)); + + assert_eq!(eval(ie, &env), Ok(EnvValue::Exp(CTrue))); + } + + #[test] + fn eval_is_error_result_false() { + let env: Environment = Environment::new(); + let aux = CInt(2); + let r = COk(Box::new(aux)); + let ie = IsError(Box::new(r)); + + assert_eq!(eval(ie, &env), Ok(EnvValue::Exp(CFalse))); + } + + #[test] + fn eval_is_error_result_error() { + let env: Environment = Environment::new(); + let aux = CInt(2); + let ie = IsError(Box::new(aux)); + + assert_eq!(eval(ie, &env), Ok(EnvValue::Exp(CFalse))); + /* + assert_eq!( + eval(ie, &env), + Err(String::from("'is_error' is only defined for Ok and Err.")) + ); */ + } + + #[test] + fn eval_is_nothing_with_nothing() { + let env: Environment = Environment::new(); + let nothing = CNothing; + let u = IsNothing(Box::new(nothing)); + + assert_eq!(eval(u, &env), Ok(EnvValue::Exp(CTrue))); + } + + #[test] + fn eval_is_nothing_with_just() { + let env: Environment = Environment::new(); + let c2 = CReal(6.9); + let just = CJust(Box::new(c2)); + let u = IsNothing(Box::new(just)); + + assert_eq!(eval(u, &env), Ok(EnvValue::Exp(CFalse))); + } + + #[test] + fn eval_is_nothing_with_int() { + let env: Environment = Environment::new(); + let c420 = CInt(420); + let u = IsNothing(Box::new(c420)); + + assert_eq!(eval(u, &env), Ok(EnvValue::Exp(CFalse))); + + //assert_eq!(eval(u, &env), Err("Expression not recognized.".to_string())); + } + #[test] fn eval_add_expression1() { let env: Environment = Environment::new(); @@ -660,7 +1092,6 @@ mod tests { assert_eq!(eval(div1, &env), Ok(EnvValue::Exp(CInt(7)))); } - #[test] fn eval_div_expression4() { let env: Environment = Environment::new(); @@ -674,7 +1105,7 @@ mod tests { Ok(EnvValue::Exp(Expression::CReal(v))) => { assert!(relative_eq!(v, 3.3333333333333335, epsilon = f64::EPSILON)) } - Err(msg) => assert!(false, "{}", msg), + Err(msg) => assert!(false, "{:?}", msg), _ => assert!(false, "Not expected."), } } @@ -724,13 +1155,13 @@ mod tests { let assign_stmt = Assignment(String::from("x"), Box::new(CInt(42)), Some(TInteger)); - match execute(assign_stmt, &env) { + match run(assign_stmt, &env) { Ok(ControlFlow::Continue(new_env)) => assert_eq!( new_env.search_frame("x".to_string()), Some(&EnvValue::Exp(CInt(42))) ), Ok(ControlFlow::Return(_)) => assert!(false), - Err(s) => assert!(false, "{}", s), + Err(s) => assert!(false, "{:?}", s), } } @@ -789,10 +1220,89 @@ mod tests { ); } Ok(ControlFlow::Return(_)) => assert!(false), + Err(s) => assert!(false, "{:?}", s), + } + } + + #[test] + fn eval_assert_true() { + //let lb= Box::new (CTrue); + //let rb= Box::new(CFalse); + let n1 = Box::new(CInt(4)); + let n2: Box = Box::new(CReal(0.54)); + let armt = Box::new(EQ(n1, n2)); + let str_erro: String = String::from("It didn't go"); + let env: Environment = Environment::new(); + let func_teste = AssertTrue(armt, str_erro.clone()); + match run(func_teste, &env) { + Ok(_) => {} + Err(s) => assert_eq!(s, str_erro), + } + } + + #[test] + fn eval_assert_false() { + let verdade = Box::new(CFalse); + let str_erro = String::from("Nao foi"); + let func_teste = AssertFalse(verdade, str_erro); + let env: Environment = Environment::new(); + match run(func_teste, &env) { + Ok(_) => {} + Err(s) => assert!(false, "{}", s), + } + } + #[test] + fn eval_assert_eq() { + let n1 = Box::new(CReal(4.0)); + let n2 = Box::new(CInt(4)); + let str_erro: String = String::from("Different values"); + let func_teste = AssertEQ(n1, n2, str_erro); + let env: Environment = Environment::new(); + + match run(func_teste, &env) { + Ok(_) => {} Err(s) => assert!(false, "{}", s), } } + #[test] + fn eval_fail_assert_eq() { + let n1 = Box::new(CReal(4.5)); + let n2 = Box::new(CInt(4)); + let str_erro: String = String::from("Different values"); + let func_teste = AssertEQ(n1, n2, str_erro.clone()); + let env: Environment = Environment::new(); + + match run(func_teste, &env) { + Ok(_) => {} + Err(s) => assert_eq!(s, str_erro), + } + } + + #[test] + fn eval_assert_neq() { + let n1 = Box::new(CReal(4.0)); + let n2 = Box::new(CInt(3)); + let str_erro: String = String::from("Equal values"); + let func_teste = AssertNEQ(n1, n2, str_erro.clone()); + let env: Environment = Environment::new(); + + match run(func_teste, &env) { + Ok(_) => {} + Err(s) => assert_eq!(s, str_erro), + } + } + #[test] + fn eval_fails() { + let env: Environment = Environment::new(); + let error_msg: String = String::from("Test failed."); + let test_fn = AssertFails(error_msg.clone()); + + match run(test_fn, &env) { + Ok(_) => {} + Err(s) => assert_eq!(s, error_msg), + } + } #[test] fn eval_simple_if_then_else() { /* @@ -822,13 +1332,13 @@ mod tests { let setup_stmt = Assignment(String::from("x"), Box::new(CInt(10)), Some(TInteger)); let program = Sequence(Box::new(setup_stmt), Box::new(if_statement)); - match execute(program, &env) { + match run(program, &env) { Ok(ControlFlow::Continue(new_env)) => assert_eq!( new_env.search_frame("y".to_string()), Some(&EnvValue::Exp(CInt(1))) ), Ok(ControlFlow::Return(_)) => assert!(false), - Err(s) => assert!(false, "{}", s), + Err(s) => assert!(false, "{:?}", s), } } @@ -878,13 +1388,13 @@ mod tests { let first_assignment = Assignment(String::from("x"), Box::new(CInt(1)), Some(TInteger)); let program = Sequence(Box::new(first_assignment), Box::new(setup_stmt)); - match execute(program, &env) { + match run(program, &env) { Ok(ControlFlow::Continue(new_env)) => assert_eq!( new_env.search_frame("y".to_string()), Some(&EnvValue::Exp(CInt(2))) ), Ok(ControlFlow::Return(_)) => assert!(false), - Err(s) => assert!(false, "{}", s), + Err(s) => assert!(false, "{:?}", s), } } @@ -928,7 +1438,7 @@ mod tests { // Box::new(Sequence(Box::new(a2), Box::new(while_statement))), // ); - // match execute(&program, env) { + // match run(&program, env) { // Ok(new_env) => { // assert_eq!(new_env.get("y"), Some(&7)); // assert_eq!(new_env.get("x"), Some(&0)); @@ -977,7 +1487,7 @@ mod tests { // Assignment(String::from("x")), Box:new(CInt(10))); // let program = Sequence(Box::new(setup_stmt), Box::new(outer_if_statement)); - // match execute(&program, env) { + // match run(&program, env) { // Ok(new_env) => assert_eq!(new_env.get("y"), Some(&1)), // Err(s) => assert!(false, "{}", s), // } @@ -1010,7 +1520,7 @@ mod tests { let program = Sequence(Box::new(a1), Box::new(Sequence(Box::new(a2), Box::new(a3)))); - match execute(program, &env) { + match run(program, &env) { Ok(ControlFlow::Continue(new_env)) => { assert_eq!( new_env.search_frame("x".to_string()), @@ -1026,7 +1536,7 @@ mod tests { ); } Ok(ControlFlow::Return(_)) => assert!(false), - Err(s) => assert!(false, "{}", s), + Err(s) => assert!(false, "{:?}", s), } } @@ -1093,34 +1603,597 @@ mod tests { )), ); - match execute(program, &env) { + match run(program, &env) { Ok(ControlFlow::Continue(new_env)) => assert_eq!( new_env.search_frame("fib".to_string()), Some(&EnvValue::Exp(CInt(34))) ), Ok(ControlFlow::Return(_)) => assert!(false), + Err(s) => assert!(false, "{:?}", s), + } + } + + #[test] + fn eval_mod_test_def() { + /* + * Test for modTest definition + * + * + * def soma1(a, b): + * return a+b + * def soma_mut(a, b, m): + * return(a+b)*m + * + * modTest teste { + * + * deftest test { + * + * assertEQ(soma1(1, 2), soma_mut(1, 2, 3)) + * } + * } + */ + + let env: Environment = Environment::new(); + + let func_soma1 = FuncDef(Function { + name: "soma1".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Add( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + ))))), + }); + + let func_soma_mut = FuncDef(Function { + name: "soma_mut".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ("m".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Mul( + Box::new(Add( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + )), + Box::new(Var("m".to_string())), + ))))), + }); + + let body_test = Box::new(AssertEQ( + Box::new(FuncCall("soma1".to_string(), vec![CInt(1), CInt(2)])), + Box::new(FuncCall( + "soma_mut".to_string(), + vec![CInt(1), CInt(2), CInt(3)], + )), + "Somas diferentes".to_string(), + )); + + let body_mod_test = Box::new(TestDef(Function { + name: "test".to_string(), + kind: Some(TVoid), + params: None, + body: Some(body_test.clone()), + })); + + let mod_test_def = Box::new(ModTestDef("teste".to_string(), body_mod_test)); + + let program = Box::new(Sequence( + Box::new(func_soma1), + Box::new(Sequence(Box::new(func_soma_mut), mod_test_def)), + )); + + let real_hash: HashMap = HashMap::from([( + "test".to_string(), + Function { + name: "test".to_string(), + kind: Some(TVoid), + params: None, + body: Some(Box::new(Sequence( + body_test, + Box::new(Return(Box::new(CVoid))), + ))), + }, + )]); + + match run(*program, &env) { + Ok(ControlFlow::Continue(new_env)) => { + let cur_scope = new_env.scope_key().clone(); + let frame = new_env.get_frame(cur_scope).clone(); + match frame.variables.get("teste") { + Some(EnvValue::TestEnvironment(mod_test)) => { + let cur_scope1 = mod_test.env.scope_key(); + let frame1 = mod_test.env.get_frame(cur_scope1); + + assert_eq!(frame1.tests, real_hash); + } + _ => assert!(false), + } + } + Ok(ControlFlow::Return(_)) => assert!(false), Err(s) => assert!(false, "{}", s), } } #[test] - fn test_metaexp_sqrt() { - let mut env = HashMap::new(); - env.insert( - "x".to_string(), - (Some(EnvValue::Exp(Expression::CReal(25.0))), Type::TReal) - ); + fn eval_more_than_one_test() { + /* + * Test for more than one function inside modTest definition + * + * + * def soma1(a, b): + * return a+b + * def soma_mut(a, b, m): + * return(a+b)*m + * def sub (a,b): + * return a-b + * def sub_mut (a,b,m): + * return (a-b)*m + * + * modTest teste { + * + * deftest test { + * + * assertEQ(soma1(1, 2), soma_mut(1, 2, 3)) + * assertNEQ(sub(1,2), submut(1,2,3)) + * } + * } + */ + let env: Environment = Environment::new(); + + let func_soma1 = FuncDef(Function { + name: "soma1".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Add( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + ))))), + }); + + let func_soma_mut = FuncDef(Function { + name: "soma_mut".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ("m".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Mul( + Box::new(Add( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + )), + Box::new(Var("m".to_string())), + ))))), + }); + + let func_sub = FuncDef(Function { + name: "sub".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Sub( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + ))))), + }); + + let func_sub_mut = FuncDef(Function { + name: "sub_mut".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ("m".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Mul( + Box::new(Sub( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + )), + Box::new(Var("m".to_string())), + ))))), + }); + + let body_test = Box::new(AssertEQ( + Box::new(FuncCall("soma1".to_string(), vec![CInt(1), CInt(2)])), + Box::new(FuncCall( + "soma_mut".to_string(), + vec![CInt(1), CInt(2), CInt(3)], + )), + "Somas diferentes".to_string(), + )); + + let body_test_1 = Box::new(AssertNEQ( + Box::new(FuncCall("sub".to_string(), vec![CInt(1), CInt(2)])), + Box::new(FuncCall( + "sub_mut".to_string(), + vec![CInt(1), CInt(2), CInt(3)], + )), + "Subtrações diferentes".to_string(), + )); + + let mut body_mod_test = Box::new(TestDef(Function { + name: "teste".to_string(), + kind: Some(TVoid), + params: None, + body: Some(body_test.clone()), + })); + + body_mod_test = Box::new(Sequence( + body_mod_test.clone(), + Box::new(TestDef(Function { + name: "teste_1".to_string(), + kind: Some(TVoid), + params: None, + body: Some(body_test_1.clone()), + })), + )); + + let mod_test_def = Box::new(ModTestDef("testes".to_string(), body_mod_test)); + let program: Box = Box::new(Sequence( + Box::new(func_soma1), + Box::new(Sequence( + Box::new(func_soma_mut), + Box::new(Sequence( + Box::new(func_sub), + Box::new(Sequence(Box::new(func_sub_mut), mod_test_def)), + )), + )), + )); + + let tests_set: Vec<(String, Option)> = vec![("testes".to_string(), None)]; + let results: HashSet<(String, String, Option)> = HashSet::from([ + ( + "testes::teste".to_string(), + "Falhou".to_string(), + Some("Erro: Somas diferentes".to_string()), + ), + ("testes::teste_1".to_string(), "Passou".to_string(), None), + ]); + + match run(*program, &env) { + Ok(ControlFlow::Continue(new_env)) => match execute_tests(tests_set, &new_env) { + Ok(result) => { + assert_eq!(results, result) + } + Err(e) => assert!(false, "{}", e), + }, + Ok(ControlFlow::Return(_)) => assert!(false), + Err(s) => assert!(false, "{}", s), + } + } + #[test] + fn eval_only_test_1() { + /* + * Test for function test_1 inside modTest definition + * + * + * def soma1(a, b): + * return a+b + * def soma_mut(a, b, m): + * return(a+b)*m + * def sub (a,b): + * return a-b + * def sub_mut (a,b,m): + * return (a-b)*m + * + * modTest testes { + * modTest teste { + * assertEQ(soma1(1, 2), soma_mut(1, 2, 3)) + * } + * modTest teste_1{ + * assertNEQ(sub(1,2), submut(1,2,3))} + * } + * } + */ + let env: Environment = Environment::new(); + + let func_soma1 = FuncDef(Function { + name: "soma1".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Add( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + ))))), + }); + + let func_soma_mut = FuncDef(Function { + name: "soma_mut".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ("m".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Mul( + Box::new(Add( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + )), + Box::new(Var("m".to_string())), + ))))), + }); + + let func_sub = FuncDef(Function { + name: "sub".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Sub( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + ))))), + }); + + let func_sub_mut = FuncDef(Function { + name: "sub_mut".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ("m".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Mul( + Box::new(Sub( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + )), + Box::new(Var("m".to_string())), + ))))), + }); + + let body_test = Box::new(AssertEQ( + Box::new(FuncCall("soma1".to_string(), vec![CInt(1), CInt(2)])), + Box::new(FuncCall( + "soma_mut".to_string(), + vec![CInt(1), CInt(2), CInt(3)], + )), + "Somas diferentes".to_string(), + )); + + let body_test_1 = Box::new(AssertNEQ( + Box::new(FuncCall("sub".to_string(), vec![CInt(1), CInt(2)])), + Box::new(FuncCall( + "sub_mut".to_string(), + vec![CInt(1), CInt(2), CInt(3)], + )), + "Subtrações diferentes".to_string(), + )); + + let body_mod_test = Box::new(Sequence( + Box::new(TestDef(Function { + name: "teste".to_string(), + kind: Some(TVoid), + params: None, + body: Some(body_test.clone()), + })), + Box::new(TestDef(Function { + name: "teste_1".to_string(), + kind: Some(TVoid), + params: None, + body: Some(body_test_1.clone()), + })), + )); + + let mod_test_def = Box::new(ModTestDef("testes".to_string(), body_mod_test)); + + let program: Box = Box::new(Sequence( + Box::new(func_soma1), + Box::new(Sequence( + Box::new(func_soma_mut), + Box::new(Sequence( + Box::new(func_sub), + Box::new(Sequence(Box::new(func_sub_mut), mod_test_def)), + )), + )), + )); + + let tests_set: Vec<(String, Option)> = + vec![("testes".to_string(), Some("teste_1".to_string()))]; + + let results: HashSet<(String, String, Option)> = + HashSet::from([("testes::teste_1".to_string(), "Passou".to_string(), None)]); + + match run(*program, &env) { + Ok(ControlFlow::Continue(new_env)) => match execute_tests(tests_set, &new_env) { + Ok(result) => { + assert_eq!(results, result) + } + Err(e) => assert!(false, "{}", e), + }, + Ok(ControlFlow::Return(_)) => assert!(false), + Err(s) => assert!(false, "{}", s), + } + } + + #[test] + fn eval_only_test() { + /* + * Test for function test inside modTest definition + * + * + * def soma1(a, b): + * return a+b + * def soma_mut(a, b, m): + * return(a+b)*m + * def sub (a,b): + * return a-b + * def sub_mut (a,b,m): + * return (a-b)*m + * + * modTest testes { + * modTest teste { + * assertEQ(soma1(1, 2), soma_mut(1, 2, 3)) + * } + * modTest teste_1{ + * assertNEQ(sub(1,2), submut(1,2,3))} + * } + * } + */ + let env: Environment = Environment::new(); + + let func_soma1 = FuncDef(Function { + name: "soma1".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Add( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + ))))), + }); + + let func_soma_mut = FuncDef(Function { + name: "soma_mut".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ("m".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Mul( + Box::new(Add( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + )), + Box::new(Var("m".to_string())), + ))))), + }); + + let func_sub = FuncDef(Function { + name: "sub".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Sub( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + ))))), + }); + + let func_sub_mut = FuncDef(Function { + name: "sub_mut".to_string(), + kind: Some(TInteger), + params: Some(vec![ + ("a".to_string(), TInteger), + ("b".to_string(), TInteger), + ("m".to_string(), TInteger), + ]), + body: Some(Box::new(Return(Box::new(Mul( + Box::new(Sub( + Box::new(Var("a".to_string())), + Box::new(Var("b".to_string())), + )), + Box::new(Var("m".to_string())), + ))))), + }); + + let body_test = Box::new(AssertEQ( + Box::new(FuncCall("soma1".to_string(), vec![CInt(1), CInt(2)])), + Box::new(FuncCall( + "soma_mut".to_string(), + vec![CInt(1), CInt(2), CInt(3)], + )), + "Somas diferentes".to_string(), + )); + + let body_test_1 = Box::new(AssertNEQ( + Box::new(FuncCall("sub".to_string(), vec![CInt(1), CInt(2)])), + Box::new(FuncCall( + "sub_mut".to_string(), + vec![CInt(1), CInt(2), CInt(3)], + )), + "Subtrações diferentes".to_string(), + )); + + let body_mod_test = Box::new(Sequence( + Box::new(TestDef(Function { + name: "teste".to_string(), + kind: Some(TVoid), + params: None, + body: Some(body_test.clone()), + })), + Box::new(TestDef(Function { + name: "teste_1".to_string(), + kind: Some(TVoid), + params: None, + body: Some(body_test_1.clone()), + })), + )); + + let mod_test_def = Box::new(ModTestDef("testes".to_string(), body_mod_test)); + + let program: Box = Box::new(Sequence( + Box::new(func_soma1), + Box::new(Sequence( + Box::new(func_soma_mut), + Box::new(Sequence( + Box::new(func_sub), + Box::new(Sequence(Box::new(func_sub_mut), mod_test_def)), + )), + )), + )); + + let tests_set: Vec<(String, Option)> = + vec![("testes".to_string(), Some("teste".to_string()))]; + + let results: HashSet<(String, String, Option)> = HashSet::from([( + "testes::teste".to_string(), + "Falhou".to_string(), + Some("Erro: Somas diferentes".to_string()), + )]); + + match run(*program, &env) { + Ok(ControlFlow::Continue(new_env)) => match execute_tests(tests_set, &new_env) { + Ok(result) => { + assert_eq!(results, result) + } + Err(e) => assert!(false, "{}", e), + }, + Ok(ControlFlow::Return(_)) => assert!(false), + Err(s) => assert!(false, "{}", s), + } + } + + #[test] + fn interpreter_metaexp_sqrt_returns_correct_value() { + let mut env = Environment::::new(); + env.insert_variable("x".to_string(), EnvValue::Exp(Expression::CReal(25.0))); + let meta_expr = Expression::MetaExp( sqrt_impl, vec![Expression::Var("x".to_string())], - Type::TReal + Type::TReal, ); - - let result = eval(meta_expr, &env).expect("Evaluation failed"); - match result { - EnvValue::Exp(Expression::CReal(value)) => assert_eq!(value, 5.0), - _ => panic!("Expected a CReal with value 5.0"), + + let result_value = eval(meta_expr, &env).expect("Evaluation failed"); + + match result_value { + EnvValue::Exp(Expression::CReal(v)) => assert!((v - 5.0).abs() < 0.0001, "Expected 5.0, got {}", v), + _ => panic!("Expected a CReal result"), } } -} +} \ No newline at end of file diff --git a/src/ir/ast.rs b/src/ir/ast.rs index d9b2b6a..659bcba 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -3,26 +3,30 @@ pub type Name = String; use nom::IResult; use std::collections::HashMap; -#[derive(Clone, Debug)] +use crate::interpreter::interpreter::EnvValue; + +#[derive(Debug, PartialEq, Clone)] pub struct Frame { pub parent_function: Option, pub parent_key: Option<(Name, i32)>, pub variables: HashMap, + pub tests: HashMap, } impl Frame { pub fn new(func: Option, key: Option<(Name, i32)>) -> Frame { let variables: HashMap = HashMap::new(); - - Frame { + let tests: HashMap = HashMap::new(); + return Frame { parent_function: func, parent_key: key, variables, - } + tests, + }; } } -#[derive(Clone, Debug)] +#[derive(Debug, PartialEq, Clone)] pub struct Environment { pub scope: Function, pub recursion: i32, @@ -34,38 +38,39 @@ impl Environment { let frame: Frame = Frame::new(None, None); let scope = Function::new(); - Environment { + return Environment { scope, recursion: 0, stack: HashMap::from([(("__main__".to_string(), 0), frame)]), - } + }; } pub fn scope_key(&self) -> (Name, i32) { - (self.scope_name(), self.recursion) + return (self.scope_name(), self.recursion); } pub fn scope_name(&self) -> Name { - self.scope.name.clone() + return self.scope.name.clone(); } pub fn scope_return(&self) -> Option<&A> { - self.search_frame(self.scope_name()) + return self.search_frame(self.scope_name()); } pub fn get_frame(&self, key: (Name, i32)) -> &Frame { - self.stack.get(&key).unwrap() + return self.stack.get(&key).unwrap(); } pub fn search_frame(&self, name: Name) -> Option<&A> { - self.stack + return self + .stack .get(&self.scope_key()) .unwrap() .variables - .get(&name) + .get(&name); } - pub fn insert_frame(&mut self, func: Function) { + pub fn insert_frame(&mut self, func: Function) -> () { let new_frame: Frame = Frame::new(Some(self.scope.clone()), Some(self.scope_key())); self.stack @@ -74,7 +79,7 @@ impl Environment { self.recursion += 1; } - pub fn remove_frame(&mut self) { + pub fn remove_frame(&mut self) -> () { let recursion = self.scope_key().1 - 1; self.scope = self .stack @@ -85,11 +90,17 @@ impl Environment { self.recursion = recursion; } - pub fn insert_variable(&mut self, name: Name, kind: A) { + pub fn insert_variable(&mut self, name: Name, kind: A) -> () { if let Some(frame) = self.stack.get_mut(&self.scope_key()) { frame.variables.insert(name, kind); } } + + pub fn insert_test(&mut self, name: Name, test: Function) -> () { + if let Some(frame) = self.stack.get_mut(&self.scope_key()) { + frame.tests.insert(name, test); + } + } } #[derive(Clone, Debug, PartialEq)] @@ -102,24 +113,42 @@ pub struct Function { impl Function { pub fn new() -> Function { - Function { + return Function { name: "__main__".to_string(), kind: None, params: None, body: None, - } + }; } } #[derive(Debug, PartialEq, Clone)] +pub struct TestEnvironment { + pub name: Name, + pub env: Environment, +} + +impl TestEnvironment { + pub fn new() -> TestEnvironment { + return TestEnvironment { + name: "__test__".to_string(), + env: Environment::::new(), + }; + } +} +#[derive(Clone, Debug, PartialEq)] pub enum Type { TInteger, TBool, TReal, TString, + TVoid, TFunction(Box>, Vec), TList(Box), TTuple(Vec), + TMaybe(Box), + TResult(Box, Box), // Ok, Error + TAny, } #[derive(Debug, PartialEq, Clone)] @@ -130,6 +159,7 @@ pub enum Expression { CInt(i32), CReal(f64), CString(String), + CVoid, /* variable reference */ Var(Name), @@ -155,6 +185,18 @@ pub enum Expression { LT(Box, Box), GTE(Box, Box), LTE(Box, Box), + + /* error expressions */ + COk(Box), + CErr(Box), + + CJust(Box), + CNothing, + + Unwrap(Box), + IsError(Box), + IsNothing(Box), + Propagate(Box), } #[derive(Debug, PartialEq, Clone)] @@ -166,6 +208,13 @@ pub enum Statement { While(Box, Box), Block(Vec), Sequence(Box, Box), + AssertTrue(Box, String), + AssertFalse(Box, String), + AssertEQ(Box, Box, String), + AssertNEQ(Box, Box, String), + TestDef(Function), + ModTestDef(Name, Box), + AssertFails(String), FuncDef(Function), Return(Box), } @@ -185,4 +234,4 @@ pub fn with_error_context<'a, T>( parser(input) .map_err(|_| nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Tag))) } -} +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index d3e030b..a794b6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,14 @@ //use crate::ir::ast::Expression; //use crate::ir::ast::Statement; //use crate::interpreter::interpreter::eval; -use crate::interpreter::interpreter::{execute, ControlFlow, EnvValue}; -use crate::ir::ast::{Environment, Expression, Statement, Type}; + +/* +use crate::interpreter::interpreter::{execute, ControlFlow}; +use crate::ir::ast::{Statement, Type}; use crate::parser::parser::parse; use std::collections::HashMap; use std::fs::File; -use std::io::Write; +use std::io::Write;*/ pub mod interpreter; pub mod ir; @@ -14,8 +16,339 @@ pub mod parser; pub mod tc; pub mod stdlib; +fn main() { + println!("Hello, world!"); +} +/* +fn run_test(name: &str, program: &str) -> String { + let mut output = String::new(); + output.push_str(&format!("\n=== Running test: {} ===\n", name)); + output.push_str(&format!("Program:\n{}\n\n", program)); + + match parse(program) { + Ok((remaining, statements)) => { + output.push_str(&format!("Parsed AST: {:#?}\n\n", statements)); + + if !remaining.is_empty() { + output.push_str(&format!( + "Warning: Unparsed input remains: {:?}\n\n", + remaining + )); + return output; + } + + let mut current_env = HashMap::new(); + + // Initialize variables + for stmt in &statements { + match stmt { + Statement::Assignment(name, _, _) => { + if !current_env.contains_key(name) { + current_env.insert(name.clone(), (None, Type::TInteger)); + } + } + Statement::FuncDef(func) => { + if !current_env.contains_key(name) { + current_env.insert(name.clone(), (None, func.kind.clone())); + } + } + Statement::IfThenElse(_, then_block, else_block) => { + // Handle variables in if blocks + if let Statement::Block(stmts) = &**then_block { + for s in stmts { + if let Statement::Assignment(name, _, _) = s { + if !current_env.contains_key(name) { + current_env.insert(name.clone(), (None, Type::TInteger)); + } + } + } + } + if let Some(else_stmt) = else_block { + if let Statement::Block(stmts) = &**else_stmt { + for s in stmts { + if let Statement::Assignment(name, _, _) = s { + if !current_env.contains_key(name) { + current_env + .insert(name.clone(), (None, Type::TInteger)); + } + } + } + } + } + } + _ => {} + } + } + + // Execute statements + for stmt in statements { + match execute(stmt, ¤t_env, false) { + Ok(ControlFlow::Continue(new_env)) => { + current_env = new_env; + } + Ok(ControlFlow::Return(value)) => { + output.push_str(&format!("Return value: {:?}\n", value)); + return output; + } + Err(e) => { + output.push_str(&format!("Execution error: {}\n", e)); + return output; + } + } + } + output.push_str(&format!("\nFinal environment: {:?}\n", current_env)); + } + Err(e) => output.push_str(&format!("Parse error: {:?}\n", e)), + } + output +} + +//raw string literal (r#""#) to avoid escaping newlines +fn main() { + // Basic Operations Tests + let test1 = r#"x = 10 +if x > 5: + y = 1 +else: + y = 2"#; + run_test("1. Basic if-else", test1); + + // Arithmetic and Parentheses Tests + let test2 = r#"x = 5 +y = 3 +z = (x * y) + (10 - 4) +w = z / (y + 1)"#; + run_test("2. Arithmetic operations", test2); + + // Nested Control Flow Tests + let test3 = r#"x = 10 +if x > 5: + if x > 8: + y = 1 + z = y + x + else: + y = 2 + z = y * x +else: + y = 3 + z = y - x"#; + run_test("3. Nested if statements with multiple operations", test3); + + // Variable Reference Tests + let test4 = r#"x = 42 +y = x +z = y + 10 +w = z +final = w * 2"#; + run_test("4. Multiple assignments and references", test4); + + // Complex Expressions Tests + let test5 = r#"a = 5 +b = 3 +c = (a * b) + (10 / 2) +d = c - (b * 2) +e = (d + a) * (b - 1)"#; + run_test("5. Complex arithmetic expressions", test5); + + // Comparison Chain Tests + let test6 = r#"x = 10 +y = 5 +if x > y: + if y > 3: + if x > 8: + z = 1 + else: + z = 2 + else: + z = 3 +else: + z = 4"#; + run_test("6. Multiple nested comparisons", test6); + + // Mixed Operations Tests + let test7 = r#"a = 15 +b = 3 +if a > 10: + c = a + b + d = c * 2 + if d > 30: + e = d - 10 + else: + e = d + 5 +else: + c = a - b + d = c / 2 + e = d * 3"#; + run_test("7. Mixed arithmetic and control flow", test7); + + let test8 = r#"def add(a: TInteger, b: TInteger) -> TInteger: + return a + b + +x = 5 +y = 3 +result = add(x, y)"#; + run_test("8. Basic function definition and call", test8); + // Recursive Function Test + let test9 = r#"def fibonacci(n: TInteger) -> TInteger: + if n < 0: + return 0 + if n <= 2: + return n - 1 + return fibonacci(n - 1) + fibonacci(n - 2) + +fib = fibonacci(10)"#; + run_test("9. Recursive function", test9); + + // Function with Multiple Returns Test + let test10 = r#"def max(a: TInteger, b: TInteger) -> TInteger: + if a > b: + return a + else: + return b + +result = max(15, 10)"#; + run_test("10. Function with multiple return paths", test10); + + // Test 11: Left recursion and operator precedence + let test11 = r#"a = 1 + 2 + 3 +b = 1 - 2 - 3 +c = 2 * 3 * 4 +d = 12 / 4 / 2 +e = 1 + 2 * 3 +f = (1 + 2) * 3 +g = 2 * 3 + 4 * 5 +h = (2 + 3) * (4 + 5)"#; + run_test("11. Left recursion and operator precedence", test11); + + // Test 12: Complex expression chains + let test12 = r#"x = 1 +y = x + 2 + 3 * 4 + 5 +z = (x + y) * 2 - 3"#; + run_test("12. Complex expression chains", test12); + + // Test 13: Mixed operator precedence + let test13 = r#"a = 10 +b = 2 +c = 3 +result = a + b * c - (a / b) + c * (a - b)"#; + run_test("13. Mixed operator precedence", test13); + + // Test 14: Deeply nested expressions + let test14 = r#"x = 2 +y = 3 +z = ((x + y) * (x - y)) / (x + 1) + y * (x + y)"#; + run_test("14. Deeply nested expressions", test14); + + // Test 15: Basic negative numbers + let test15 = r#"a = -5 +b = -10 +c = -15 +result = a + b + c"#; + run_test("15. Basic negative numbers", test15); + + // Test 16: Mixed positive and negative operations + let test16 = r#"x = 10 +y = -3 +z = x + y * -2 +w = -x + (-y * 2)"#; + run_test("16. Mixed positive and negative operations", test16); + + // Test 17: Negative numbers in complex expressions + let test17 = r#"a = -2 +b = 3 +c = (-a * b) + (-4 * -5) +d = (a + -b) * (-2 + b)"#; + run_test("17. Complex expressions with negatives", test17); + + // Test 18: Negative numbers in function calls + let test18 = r#"def subtract(a: TInteger, b: TInteger) -> TInteger: + return a - b + +result1 = subtract(-10, -3) +result2 = subtract(5, -3) +result3 = subtract(-5, 3)"#; + run_test("18. Function calls with negative numbers", test18); + + // Test 19: Boolean Operations + let test19 = r#"a = True +b = False +c = True and False +d = True or False +e = not False +f = not (True and False) or True"#; + run_test("19. Boolean Operations", test19); + + // Test 20: Real Numbers + let test20 = r#"x = 3.14 +y = -2.5 +z = x + y +w = x * 2.0 +v = 10.5 / 2.1"#; + run_test("20. Real Number Operations", test20); + + // Test 21: String Operations + let test21 = r#"name = "Hello" +greeting = "World" +message = "Test ""#; + run_test("21. String Operations", test21); + + // Test 22: Mixed Boolean Operations + let test22 = r#"x = 10 +y = 5 +result1 = x > y and True +result2 = (x < y) or True +result3 = not (x <= y) +result4 = (x >= y) and (not False)"#; + run_test("22. Mixed Boolean Operations", test22); + + let mut all_results = String::new(); + + all_results.push_str(&run_test("1. Basic if-else", test1)); + all_results.push_str(&run_test("2. Arithmetic operations", test2)); + all_results.push_str(&run_test( + "3. Nested if statements with multiple operations", + test3, + )); + all_results.push_str(&run_test("4. Multiple assignments and references", test4)); + all_results.push_str(&run_test("5. Complex arithmetic expressions", test5)); + all_results.push_str(&run_test("6. Multiple nested comparisons", test6)); + all_results.push_str(&run_test("7. Mixed arithmetic and control flow", test7)); + all_results.push_str(&run_test("8. Basic function definition and call", test8)); + all_results.push_str(&run_test("9. Recursive function", test9)); + all_results.push_str(&run_test("10. Function with multiple return paths", test10)); + all_results.push_str(&run_test( + "11. Left recursion and operator precedence", + test11, + )); + all_results.push_str(&run_test("12. Complex expression chains", test12)); + all_results.push_str(&run_test("13. Mixed operator precedence", test13)); + all_results.push_str(&run_test("14. Deeply nested expressions", test14)); + all_results.push_str(&run_test("15. Basic negative numbers", test15)); + all_results.push_str(&run_test( + "16. Mixed positive and negative operations", + test16, + )); + all_results.push_str(&run_test("17. Complex expressions with negatives", test17)); + all_results.push_str(&run_test( + "18. Function calls with negative numbers", + test18, + )); + all_results.push_str(&run_test("19. Boolean Operations", test19)); + all_results.push_str(&run_test("20. Real Number Operations", test20)); + all_results.push_str(&run_test("21. String Operations", test21)); + all_results.push_str(&run_test("22. Mixed Boolean Operations", test22)); + + // Write results to file + let mut file = File::create("test_results.txt").expect("Failed to create file"); + file.write_all(all_results.as_bytes()) + .expect("Failed to write to file"); + + // Also print to console + print!("{}", all_results); +} +/* fn run_test(name: &str, program: &str) -> String { let mut output = String::new(); output.push_str(&format!("\n=== Running test: {} ===\n", name)); @@ -350,3 +683,4 @@ result4 = (x >= y) and (not False)"#; // Also print to console print!("{}", all_results); } + */ */ \ No newline at end of file diff --git a/src/parser/parser.rs b/src/parser/parser.rs index bec0bbf..f546b10 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -3,7 +3,7 @@ use nom::{ bytes::complete::{tag, take_while, take_while1}, character::complete::{char, digit1, line_ending, space0, space1}, combinator::{map, map_res, opt, recognize}, - error::{Error, ErrorKind}, + error::Error, multi::{many0, many1, separated_list0, separated_list1}, sequence::{delimited, pair, preceded, tuple}, IResult, @@ -11,13 +11,43 @@ use nom::{ type ParseResult<'a, T> = IResult<&'a str, T, Error<&'a str>>; +const KEYWORDS: &[&str] = &[ + "if", + "else", + "def", + "while", + "val", + "var", + "return", + "Ok", + "Err", + "Just", + "Nothing", + "unwrap", + "tryUnwrap", + "isNothing", + "isError", + "and", + "or", + "not", + "True", + "False", +]; + use crate::ir::ast::Function; use crate::ir::ast::Type; use crate::ir::ast::{Expression, Name, Statement}; -// Parse identifier fn identifier(input: &str) -> IResult<&str, Name> { let (input, id) = take_while1(|c: char| c.is_alphanumeric() || c == '_')(input)?; + + if KEYWORDS.contains(&id) { + return Err(nom::Err::Error(Error { + input, + code: nom::error::ErrorKind::Tag, + })); + } + Ok((input, id.to_string())) } @@ -85,6 +115,14 @@ fn expression(input: &str) -> IResult<&str, Expression> { arithmetic_expression, real, integer, + ok_expression, + err_expression, + just_expression, + nothing_expression, + unwrap_expression, + tryunwrap_expression, + iserror_expression, + isnothing_expression, string, map(identifier, Expression::Var), ))(input) @@ -114,7 +152,6 @@ fn comparison_expression(input: &str) -> IResult<&str, Expression> { let (input, op) = comparison_operator(input)?; let (input, _) = space0(input)?; let (input, right) = term(input)?; - Ok(( input, match op { @@ -186,6 +223,94 @@ fn string(input: &str) -> IResult<&str, Expression> { )(input) } +fn ok_expression(input: &str) -> IResult<&str, Expression> { + let (input, _) = tag("Ok")(input)?; + let (input, _) = space0(input)?; + let (input, expr) = delimited( + tuple((char('('), space0)), + expression, + tuple((space0, char(')'))), + )(input)?; + + Ok((input, Expression::COk(Box::new(expr)))) +} + +fn err_expression(input: &str) -> IResult<&str, Expression> { + let (input, _) = tag("Err")(input)?; + let (input, _) = space0(input)?; + let (input, expr) = delimited( + tuple((char('('), space0)), + expression, + tuple((space0, char(')'))), + )(input)?; + + Ok((input, Expression::CErr(Box::new(expr)))) +} + +fn just_expression(input: &str) -> IResult<&str, Expression> { + let (input, _) = tag("Just")(input)?; + let (input, _) = space0(input)?; + let (input, expr) = delimited( + tuple((char('('), space0)), + expression, + tuple((space0, char(')'))), + )(input)?; + Ok((input, Expression::CJust(Box::new(expr)))) +} + +fn nothing_expression(input: &str) -> IResult<&str, Expression> { + map(tag("Nothing"), |_| Expression::CNothing)(input) +} + +fn isnothing_expression(input: &str) -> IResult<&str, Expression> { + let (input, _) = tag("isNothing")(input)?; + let (input, _) = space0(input)?; + + let (input, expr) = delimited( + tuple((char('('), space0)), + expression, + tuple((space0, char(')'))), + )(input)?; + + Ok((input, Expression::IsNothing(Box::new(expr)))) +} + +fn iserror_expression(input: &str) -> IResult<&str, Expression> { + let (input, _) = tag("isError")(input)?; + let (input, _) = space0(input)?; + let (input, expr) = delimited( + tuple((char('('), space0)), + expression, + tuple((space0, char(')'))), + )(input)?; + + Ok((input, Expression::IsError(Box::new(expr)))) +} + +fn unwrap_expression(input: &str) -> IResult<&str, Expression> { + let (input, _) = tag("unwrap")(input)?; + let (input, _) = space0(input)?; + let (input, expr) = delimited( + tuple((char('('), space0)), + expression, + tuple((space0, char(')'))), + )(input)?; + + Ok((input, Expression::Unwrap(Box::new(expr)))) +} + +fn tryunwrap_expression(input: &str) -> IResult<&str, Expression> { + let (input, _) = tag("tryUnwrap")(input)?; + let (input, _) = space0(input)?; + let (input, expr) = delimited( + tuple((char('('), space0)), + expression, + tuple((space0, char(')'))), + )(input)?; + + Ok((input, Expression::Propagate(Box::new(expr)))) +} + // Parse boolean operations fn boolean_expression(input: &str) -> IResult<&str, Expression> { let (input, first) = boolean_term(input)?; @@ -217,6 +342,10 @@ fn boolean_factor(input: &str) -> IResult<&str, Expression> { alt(( boolean, comparison_expression, + unwrap_expression, + tryunwrap_expression, + iserror_expression, + isnothing_expression, delimited( tuple((char('('), space0)), boolean_expression, @@ -233,6 +362,14 @@ fn factor(input: &str) -> IResult<&str, Expression> { tuple((space0, char(')'))), ), function_call, + ok_expression, + err_expression, + just_expression, + nothing_expression, + unwrap_expression, + tryunwrap_expression, + iserror_expression, + isnothing_expression, real, integer, map(tuple((char('-'), space0, factor)), |(_, _, expr)| { @@ -258,7 +395,11 @@ fn indented_block(input: &str) -> IResult<&str, Vec> { fn if_statement(input: &str) -> IResult<&str, Statement> { let (input, _) = tag("if")(input)?; let (input, _) = space1(input)?; - let (input, condition) = comparison_expression(input)?; + let (input, condition) = alt(( + comparison_expression, + boolean_expression, + map(identifier, Expression::Var), + ))(input)?; let (input, _) = space0(input)?; let (input, _) = char(':')(input)?; let (input, then_block) = indented_block(input)?; @@ -653,7 +794,7 @@ mod tests { Statement::FuncDef(func) => { assert_eq!(func.name, "add"); assert_eq!(func.kind, Some(Type::TInteger)); - match &func.params { + match func.params { Some(params) => { assert_eq!(params.len(), 2); assert_eq!(params[0].0, "x"); @@ -661,6 +802,15 @@ mod tests { } None => panic!("Expected Some params"), } + assert_eq!( + func.body, + Some(Box::new(Statement::Block(vec![Statement::Return( + Box::new(Expression::Add( + Box::new(Expression::Var("x".to_string())), + Box::new(Expression::Var("y".to_string())) + )) + )]))) + ); } _ => panic!("Expected FuncDef"), } @@ -882,4 +1032,328 @@ mod tests { assert_eq!(rest, ""); assert_eq!(result, expected); } -} + + #[test] + fn test_eval_iserror_err_expression() { + let input = "isError (Err (1))"; + let (rest, result) = iserror_expression(input).unwrap(); + let expected = + Expression::IsError(Box::new(Expression::CErr(Box::new(Expression::CInt(1))))); + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + + #[test] + fn test_eval_iserror_ok_expression() { + let input = "isError (Ok (2))"; + let (rest, result) = iserror_expression(input).unwrap(); + let expected = + Expression::IsError(Box::new(Expression::COk(Box::new(Expression::CInt(2))))); + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + + #[test] + fn test_eval_iserror_real() { + let input = "isError (3.14)"; + let (rest, result) = iserror_expression(input).unwrap(); + let expected = Expression::IsError(Box::new(Expression::CReal(3.14))); + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + + #[test] + fn test_eval_isnothing_nothing_expression() { + let input = "isNothing(Nothing)"; + let (rest, result) = isnothing_expression(input).unwrap(); + let expected = Expression::IsNothing(Box::new(Expression::CNothing)); + assert_eq!(rest, ""); + assert_eq!(result, expected); + //Necessita da implementação de definição de Nothing. + } + + #[test] + fn test_eval_isnothing_just_expression() { + let input = "isNothing (Just (2))"; + let (rest, result) = isnothing_expression(input).unwrap(); + let expected = + Expression::IsNothing(Box::new(Expression::CJust(Box::new(Expression::CInt(2))))); + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + + #[test] + fn test_eval_isnothing_real() { + let input = "isNothing (4.20)"; + let (rest, result) = isnothing_expression(input).unwrap(); + let expected = Expression::IsNothing(Box::new(Expression::CReal(4.20))); + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + + #[test] + fn test_ok_creation() { + let cases = vec![ + ("Ok(1)", Expression::COk(Box::new(Expression::CInt(1)))), + ("Ok(0.5)", Expression::COk(Box::new(Expression::CReal(0.5)))), + ("Err(False)", Expression::CErr(Box::new(Expression::CFalse))), + ]; + + for (input, expected) in cases { + let (rest, result) = expression(input).unwrap(); + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + } + + #[test] + fn test_try_unwrap_expression() { + let input = "tryUnwrap(Ok(42))"; + let expected = + Expression::Propagate(Box::new(Expression::COk(Box::new(Expression::CInt(42))))); + + let (remaining, parsed) = tryunwrap_expression(input).expect("Parsing failed"); + + assert_eq!(parsed, expected); + assert!( + remaining.is_empty(), + "Remaining input should be empty but got: {}", + remaining + ); + } + + #[test] + fn test_unwrap_parsing() { + let cases = vec![ + ( + "unwrap(Ok(2))", + Expression::Unwrap(Box::new(Expression::COk(Box::new(Expression::CInt(2))))), + ), + ( + "unwrap(Ok(2.5))", + Expression::Unwrap(Box::new(Expression::COk(Box::new(Expression::CReal(2.5))))), + ), + ( + "unwrap(3)", + Expression::Unwrap(Box::new(Expression::CInt(3))), + ), + ( + "unwrap(3.5)", + Expression::Unwrap(Box::new(Expression::CReal(3.5))), + ), + ]; + + for (input, expected) in cases { + let (rest, result) = unwrap_expression(input).unwrap(); + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + } + + #[test] + fn test_propagation_parsing() { + let cases = vec![ + ( + "tryUnwrap(Ok(2))", + Expression::Propagate(Box::new(Expression::COk(Box::new(Expression::CInt(2))))), + ), + ( + "tryUnwrap(tryUnwrap(x))", + Expression::Propagate(Box::new(Expression::Propagate(Box::new(Expression::Var( + String::from("x"), + ))))), + ), + ( + "tryUnwrap(Ok(10.1 + 1.2))", + Expression::Propagate(Box::new(Expression::COk(Box::new(Expression::Add( + Box::new(Expression::CReal(10.1)), + Box::new(Expression::CReal(1.2)), + ))))), + ), + /*( + "tryUnwrap(Ok(1)) / tryUnwrap(Just(2))", + Expression::Div( + Box::new(Expression::Propagate(Box::new(Expression::COk(Box::new( + Expression::CInt(1), + ))))), + Box::new(Expression::Propagate(Box::new(Expression::CJust( + Box::new(Expression::CInt(2)), + )))), + ), + ),*/ + ( + "tryUnwrap(Ok(True)) and tryUnwrap(Ok(False))", + Expression::And( + Box::new(Expression::Propagate(Box::new(Expression::COk(Box::new( + Expression::CTrue, + ))))), + Box::new(Expression::Propagate(Box::new(Expression::COk(Box::new( + Expression::CFalse, + ))))), + ), + ), + ( + "tryUnwrap(tryUnwrap(Ok(True or False)))", + Expression::Propagate(Box::new(Expression::Propagate(Box::new(Expression::COk( + Box::new(Expression::Or( + Box::new(Expression::CTrue), + Box::new(Expression::CFalse), + )), + ))))), + ), + ( + "tryUnwrap(Just(not False))", + Expression::Propagate(Box::new(Expression::CJust(Box::new(Expression::Not( + Box::new(Expression::CFalse), + ))))), + ), + ]; + + for (input, expected) in cases { + let (rest, result) = expression(input).unwrap(); + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + } + + #[test] + fn test_propagation_parsing_statements() { + let input = "x = Ok(True)\nif unwrap(x):\n y = 1\nif tryUnwrap(x):\n y = 1\n"; + + let (rest, result) = parse(input).unwrap(); + assert_eq!(rest, ""); + assert_eq!( + result, + [ + Statement::Assignment( + String::from("x"), + Box::new(Expression::COk(Box::new(Expression::CTrue))), + None + ), + Statement::IfThenElse( + Box::new(Expression::Unwrap(Box::new(Expression::Var(String::from( + "x" + ))))), + Box::new(Statement::Block(vec![Statement::Assignment( + String::from("y"), + Box::new(Expression::CInt(1)), + Some(Type::TInteger) + )])), + None + ), + Statement::IfThenElse( + Box::new(Expression::Propagate(Box::new(Expression::Var( + String::from("x") + )))), + Box::new(Statement::Block(vec![Statement::Assignment( + String::from("y"), + Box::new(Expression::CInt(1)), + Some(Type::TInteger) + )])), + None + ) + ] + ); + } + + #[test] + fn test_eval_just_integer() { + let input = "Just (42)"; + let (rest, result) = just_expression(input).unwrap(); + let expected = Expression::CJust(Box::new(Expression::CInt(42))); + + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + + #[test] + fn test_eval_just_real() { + let input = "Just (3.14)"; + let (rest, result) = just_expression(input).unwrap(); + let expected = Expression::CJust(Box::new(Expression::CReal(3.14))); + + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + + #[test] + fn test_eval_just_expression() { + let input = "Just (1 + 2)"; + let (rest, result) = just_expression(input).unwrap(); + let expected = Expression::CJust(Box::new(Expression::Add( + Box::new(Expression::CInt(1)), + Box::new(Expression::CInt(2)), + ))); + + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + + #[test] + fn test_eval_nothing() { + let input = "Nothing"; + let (rest, result) = nothing_expression(input).unwrap(); + let expected = Expression::CNothing; + + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + + #[test] + fn test_eval_isnothing_nothing() { + let input = "isNothing (Nothing)"; + let (rest, result) = isnothing_expression(input).unwrap(); + let expected = Expression::IsNothing(Box::new(Expression::CNothing)); + + assert_eq!(rest, ""); + assert_eq!(result, expected); + } + + #[test] + fn test_create_function_with_keyword_if() { + let input = "def if(x: TInteger) -> TInteger:\n return x"; + let result = function_def(input); + + assert!(result.is_err()); + } + + #[test] + fn test_create_function_with_keyword_while() { + let input = "def while(x: TInteger) -> TInteger:\n return x"; + let result = function_def(input); + + assert!(result.is_err()); + } + + #[test] + fn test_create_function_with_keyword_ok() { + let input = "def Ok(x: TInteger) -> TInteger:\n return x"; + let result = function_def(input); + + assert!(result.is_err()); + } + + #[test] + fn test_var_declaration_with_keyword_if() { + let input = "if = 10"; + let result = assignment(input); + + assert!(result.is_err()); + } + + #[test] + fn test_var_declaration_with_keyword_while() { + let input = "while = 10"; + let result = assignment(input); + + assert!(result.is_err()); + } + + #[test] + fn test_var_declaration_with_keyword_ok() { + let input = "Ok = 10"; + let result = assignment(input); + + assert!(result.is_err()); + } +} \ No newline at end of file diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs index 04329f4..cd61489 100644 --- a/src/stdlib/math.rs +++ b/src/stdlib/math.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::ir::ast::{EnvValue, Expression, Function, Statement, Type}; - +use crate::ir::ast::{Expression, Function, Statement, Type}; +use crate::interpreter::interpreter::EnvValue; pub fn load_math_stdlib() -> HashMap { let mut math_stdlib = HashMap::new(); @@ -8,117 +8,130 @@ pub fn load_math_stdlib() -> HashMap { math_stdlib.insert( "sqrt".to_string(), Function { - kind: Type::TReal, + name: "sqrt".to_string(), + kind: Some(Type::TReal), params: Some(vec![("x".to_string(), Type::TReal)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(sqrt_impl, vec![Expression::Var("x".to_string())], Type::TReal)))), + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(sqrt_impl, vec![Expression::Var("x".to_string())], Type::TReal))))), } ); math_stdlib.insert( "factorial".to_string(), Function { - kind: Type::TInteger, + name: "factorial".to_string(), + kind: Some(Type::TInteger), params: Some(vec![("n".to_string(), Type::TInteger)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(factorial_impl, vec![Expression::Var("x".to_string())], Type::TInteger)))), + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(factorial_impl, vec![Expression::Var("x".to_string())], Type::TInteger))))), } ); math_stdlib.insert( "gcd".to_string(), Function { - kind: Type::TInteger, + name: "gcd".to_string(), + kind: Some(Type::TInteger), params: Some(vec![("a".to_string(), Type::TInteger), ("b".to_string(), Type::TInteger)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(gcd_impl, vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], Type::TInteger)))), + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(gcd_impl, vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], Type::TInteger))))), } ); math_stdlib.insert( "lcm".to_string(), Function { - kind: Type::TInteger, + name: "lcm".to_string(), + kind: Some(Type::TInteger), params: Some(vec![("a".to_string(), Type::TInteger), ("b".to_string(), Type::TInteger)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(lcm_impl, vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], Type::TInteger)))), + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(lcm_impl, vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], Type::TInteger))))), } ); math_stdlib.insert( "is_prime".to_string(), Function { - kind: Type::TBool, + name: "is_prime".to_string(), + kind: Some(Type::TBool), params: Some(vec![("x".to_string(), Type::TInteger)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(is_prime_impl, vec![Expression::Var("x".to_string())], Type::TBool)))), + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(is_prime_impl, vec![Expression::Var("x".to_string())], Type::TBool))))), } ); math_stdlib.insert( "comb".to_string(), Function { - kind: Type::TInteger, + name: "comb".to_string(), + kind: Some(Type::TInteger), params: Some(vec![("n".to_string(), Type::TInteger), ("k".to_string(), Type::TInteger)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(comb_impl, vec![Expression::Var("n".to_string()), Expression::Var("r".to_string())], Type::TInteger)))) + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(comb_impl, vec![Expression::Var("n".to_string()), Expression::Var("r".to_string())], Type::TInteger))))) } ); math_stdlib.insert( "perm".to_string(), Function { - kind: Type::TInteger, + name: "perm".to_string(), + kind: Some(Type::TInteger), params: Some(vec![("n".to_string(), Type::TInteger), ("k".to_string(), Type::TInteger)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(perm_impl, vec![Expression::Var("n".to_string()), Expression::Var("r".to_string())], Type::TInteger)))) + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(perm_impl, vec![Expression::Var("n".to_string()), Expression::Var("r".to_string())], Type::TInteger))))) } ); math_stdlib.insert( "log".to_string(), Function { - kind: Type::TReal, + name: "log".to_string(), + kind: Some(Type::TReal), params: Some(vec![("x".to_string(), Type::TReal), ("base".to_string(), Type::TReal)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(log_impl, vec![Expression::Var("x".to_string()), Expression::Var("base".to_string())], Type::TReal)))) + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(log_impl, vec![Expression::Var("x".to_string()), Expression::Var("base".to_string())], Type::TReal))))) } ); math_stdlib.insert( "degrees".to_string(), Function { - kind: Type::TReal, + name: "degrees".to_string(), + kind: Some(Type::TReal), params: Some(vec![("rad".to_string(), Type::TReal)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(degrees_impl, vec![Expression::Var("rad".to_string())], Type::TReal)))) + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(degrees_impl, vec![Expression::Var("rad".to_string())], Type::TReal))))) } ); math_stdlib.insert( "radians".to_string(), Function { - kind: Type::TReal, + name: "radians".to_string(), + kind: Some(Type::TReal), params: Some(vec![("deg".to_string(), Type::TReal)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(radians_impl, vec![Expression::Var("deg".to_string())], Type::TReal)))) + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(radians_impl, vec![Expression::Var("deg".to_string())], Type::TReal))))) } ); math_stdlib.insert( "cos".to_string(), Function { - kind: Type::TReal, + name: "cos".to_string(), + kind: Some(Type::TReal), params: Some(vec![("x".to_string(), Type::TReal)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(cos_impl, vec![Expression::Var("x".to_string())], Type::TReal)))) + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(cos_impl, vec![Expression::Var("x".to_string())], Type::TReal))))) } ); math_stdlib.insert( "sin".to_string(), Function { - kind: Type::TReal, + name: "sin".to_string(), + kind: Some(Type::TReal), params: Some(vec![("x".to_string(), Type::TReal)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(sin_impl, vec![Expression::Var("x".to_string())], Type::TReal)))) + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(sin_impl, vec![Expression::Var("x".to_string())], Type::TReal))))) } ); math_stdlib.insert( "tan".to_string(), Function { - kind: Type::TReal, + name: "tan".to_string(), + kind: Some(Type::TReal), params: Some(vec![("x".to_string(), Type::TReal)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp(tan_impl, vec![Expression::Var("x".to_string())], Type::TReal)))) + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(tan_impl, vec![Expression::Var("x".to_string())], Type::TReal))))) } ); diff --git a/src/stdlib/stdlib.rs b/src/stdlib/stdlib.rs index 1319d63..98d768a 100644 --- a/src/stdlib/stdlib.rs +++ b/src/stdlib/stdlib.rs @@ -21,7 +21,7 @@ pub fn load_stdlib() -> HashMap { } #[cfg(test)] -mod stdlib_tests { +mod tests { use crate::ir::ast::{Statement, Expression, Type}; use crate::stdlib::math::load_math_stdlib; use crate::stdlib::string::load_string_stdlib; @@ -31,14 +31,14 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let sqrt_func = math_stdlib.get("sqrt").expect("Function 'sqrt' not found in math stdlib"); - assert_eq!(sqrt_func.kind, Type::TReal); + assert_eq!(sqrt_func.kind, Some(Type::TReal)); let params = sqrt_func.params.as_ref().expect("Expected parameters for sqrt"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TReal); - match *sqrt_func.body { + match sqrt_func.body.as_ref().expect("Expected body for sqrt").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -57,14 +57,14 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let factorial_func = math_stdlib.get("factorial").expect("Function 'factorial' not found in math stdlib"); - assert_eq!(factorial_func.kind, Type::TInteger); + assert_eq!(factorial_func.kind, Some(Type::TInteger)); let params = factorial_func.params.as_ref().expect("Expected parameters for factorial"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "n"); assert_eq!(params[0].1, Type::TInteger); - match *factorial_func.body { + match factorial_func.body.as_ref().expect("Expected body for factorial").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -83,7 +83,7 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let gcd_func = math_stdlib.get("gcd").expect("Function 'gcd' not found in math stdlib"); - assert_eq!(gcd_func.kind, Type::TInteger); + assert_eq!(gcd_func.kind, Some(Type::TInteger)); let params = gcd_func.params.as_ref().expect("Expected parameters for gcd"); assert_eq!(params.len(), 2); @@ -92,7 +92,7 @@ mod stdlib_tests { assert_eq!(params[1].0, "b"); assert_eq!(params[1].1, Type::TInteger); - match *gcd_func.body { + match gcd_func.body.as_ref().expect("Expected body for gcd").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -111,7 +111,7 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let lcm_func = math_stdlib.get("lcm").expect("Function 'lcm' not found in math stdlib"); - assert_eq!(lcm_func.kind, Type::TInteger); + assert_eq!(lcm_func.kind, Some(Type::TInteger)); let params = lcm_func.params.as_ref().expect("Expected parameters for lcm"); assert_eq!(params.len(), 2); @@ -120,7 +120,7 @@ mod stdlib_tests { assert_eq!(params[1].0, "b"); assert_eq!(params[1].1, Type::TInteger); - match *lcm_func.body { + match lcm_func.body.as_ref().expect("Expected body for lcm").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -139,7 +139,7 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let comb_func = math_stdlib.get("comb").expect("Function 'comb' not found in math stdlib"); - assert_eq!(comb_func.kind, Type::TInteger); + assert_eq!(comb_func.kind, Some(Type::TInteger)); let params = comb_func.params.as_ref().expect("Expected parameters for comb"); assert_eq!(params.len(), 2); @@ -148,7 +148,7 @@ mod stdlib_tests { assert_eq!(params[1].0, "k"); assert_eq!(params[1].1, Type::TInteger); - match *comb_func.body { + match comb_func.body.as_ref().expect("Expected body for comb").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -167,7 +167,7 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let perm_func = math_stdlib.get("perm").expect("Function 'perm' not found in math stdlib"); - assert_eq!(perm_func.kind, Type::TInteger); + assert_eq!(perm_func.kind, Some(Type::TInteger)); let params = perm_func.params.as_ref().expect("Expected parameters for perm"); assert_eq!(params.len(), 2); @@ -176,7 +176,7 @@ mod stdlib_tests { assert_eq!(params[1].0, "k"); assert_eq!(params[1].1, Type::TInteger); - match *perm_func.body { + match perm_func.body.as_ref().expect("Expected body for perm").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -195,14 +195,14 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let is_prime_func = math_stdlib.get("is_prime").expect("Function 'is_prime' not found in math stdlib"); - assert_eq!(is_prime_func.kind, Type::TBool); + assert_eq!(is_prime_func.kind, Some(Type::TBool)); let params = is_prime_func.params.as_ref().expect("Expected parameters for is_prime"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TInteger); - match *is_prime_func.body { + match is_prime_func.body.as_ref().expect("Expected body for is_prime").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -221,7 +221,7 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let log_func = math_stdlib.get("log").expect("Function 'log' not found in math stdlib"); - assert_eq!(log_func.kind, Type::TReal); + assert_eq!(log_func.kind, Some(Type::TReal)); let params = log_func.params.as_ref().expect("Expected parameters for log"); assert_eq!(params.len(), 2); @@ -230,7 +230,7 @@ mod stdlib_tests { assert_eq!(params[1].0, "base"); assert_eq!(params[1].1, Type::TReal); - match *log_func.body { + match log_func.body.as_ref().expect("Expected body for log").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -249,14 +249,14 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let degrees_func = math_stdlib.get("degrees").expect("Function 'degrees' not found in math stdlib"); - assert_eq!(degrees_func.kind, Type::TReal); + assert_eq!(degrees_func.kind, Some(Type::TReal)); let params = degrees_func.params.as_ref().expect("Expected parameters for degrees"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "rad"); assert_eq!(params[0].1, Type::TReal); - match *degrees_func.body { + match degrees_func.body.as_ref().expect("Expected body for degrees").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -275,14 +275,14 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let radians_func = math_stdlib.get("radians").expect("Function 'radians' not found in math stdlib"); - assert_eq!(radians_func.kind, Type::TReal); + assert_eq!(radians_func.kind, Some(Type::TReal)); let params = radians_func.params.as_ref().expect("Expected parameters for radians"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "deg"); assert_eq!(params[0].1, Type::TReal); - match *radians_func.body { + match radians_func.body.as_ref().expect("Expected body for radians").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -301,14 +301,14 @@ mod stdlib_tests { let string_stdlib = load_string_stdlib(); let str_upper_func = string_stdlib.get("str_upper").expect("Function 'str_upper' not found in string stdlib"); - assert_eq!(str_upper_func.kind, Type::TString); + assert_eq!(str_upper_func.kind, Some(Type::TString)); let params = str_upper_func.params.as_ref().expect("Expected parameters for str_upper"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); - match *str_upper_func.body { + match str_upper_func.body.as_ref().expect("Expected body for str_upper").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -327,14 +327,14 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let cos_func = math_stdlib.get("cos").expect("Function 'cos' not found in math stdlib"); - assert_eq!(cos_func.kind, Type::TReal); + assert_eq!(cos_func.kind, Some(Type::TReal)); let params = cos_func.params.as_ref().expect("Expected parameters for cos"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TReal); - match *cos_func.body { + match cos_func.body.as_ref().expect("Expected body for cos").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -353,14 +353,14 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let sin_func = math_stdlib.get("sin").expect("Function 'sin' not found in math stdlib"); - assert_eq!(sin_func.kind, Type::TReal); + assert_eq!(sin_func.kind, Some(Type::TReal)); let params = sin_func.params.as_ref().expect("Expected parameters for sin"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TReal); - match *sin_func.body { + match sin_func.body.as_ref().expect("Expected body for sin").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -379,14 +379,14 @@ mod stdlib_tests { let math_stdlib = load_math_stdlib(); let tan_func = math_stdlib.get("tan").expect("Function 'tan' not found in math stdlib"); - assert_eq!(tan_func.kind, Type::TReal); + assert_eq!(tan_func.kind, Some(Type::TReal)); let params = tan_func.params.as_ref().expect("Expected parameters for tan"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TReal); - match *tan_func.body { + match tan_func.body.as_ref().expect("Expected body for tan").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -405,14 +405,14 @@ mod stdlib_tests { let string_stdlib = load_string_stdlib(); let str_lower_func = string_stdlib.get("str_lower").expect("Function 'str_lower' not found in string stdlib"); - assert_eq!(str_lower_func.kind, Type::TString); + assert_eq!(str_lower_func.kind, Some(Type::TString)); let params = str_lower_func.params.as_ref().expect("Expected parameters for str_lower"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); - match *str_lower_func.body { + match str_lower_func.body.as_ref().expect("Expected body for str_lower").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -430,14 +430,14 @@ mod stdlib_tests { let string_stdlib = load_string_stdlib(); let str_length_func = string_stdlib.get("str_length").expect("Function 'str_length' not found in string stdlib"); - assert_eq!(str_length_func.kind, Type::TInteger); + assert_eq!(str_length_func.kind, Some(Type::TInteger)); let params = str_length_func.params.as_ref().expect("Expected parameters for str_length"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); - match *str_length_func.body { + match str_length_func.body.as_ref().expect("Expected body for str_length").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -456,14 +456,14 @@ mod stdlib_tests { let string_stdlib = load_string_stdlib(); let str_reverse_func = string_stdlib.get("str_reverse").expect("Function 'str_reverse' not found in string stdlib"); - assert_eq!(str_reverse_func.kind, Type::TString); + assert_eq!(str_reverse_func.kind, Some(Type::TString)); let params = str_reverse_func.params.as_ref().expect("Expected parameters for str_reverse"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); - match *str_reverse_func.body { + match str_reverse_func.body.as_ref().expect("Expected body for str_reverse").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -482,7 +482,7 @@ mod stdlib_tests { let string_stdlib = load_string_stdlib(); let cont_chars_func = string_stdlib.get("cont_chars").expect("Function 'cont_chars' not found in string stdlib"); - assert_eq!(cont_chars_func.kind, Type::TInteger); + assert_eq!(cont_chars_func.kind, Some(Type::TInteger)); let params = cont_chars_func.params.as_ref().expect("Expected parameters for cont_chars"); assert_eq!(params.len(), 2); @@ -491,7 +491,7 @@ mod stdlib_tests { assert_eq!(params[1].0, "c"); assert_eq!(params[1].1, Type::TString); - match *cont_chars_func.body { + match cont_chars_func.body.as_ref().expect("Expected body for cont_chars").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -510,7 +510,7 @@ mod stdlib_tests { let string_stdlib = load_string_stdlib(); let filter_out_char_func = string_stdlib.get("filter_out_char").expect("Function 'filter_out_char' not found in string stdlib"); - assert_eq!(filter_out_char_func.kind, Type::TString); + assert_eq!(filter_out_char_func.kind, Some(Type::TString)); let params = filter_out_char_func.params.as_ref().expect("Expected parameters for filter_out_char"); assert_eq!(params.len(), 2); @@ -519,7 +519,7 @@ mod stdlib_tests { assert_eq!(params[1].0, "c"); assert_eq!(params[1].1, Type::TString); - match *filter_out_char_func.body { + match filter_out_char_func.body.as_ref().expect("Expected body for filter_out_char").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { @@ -538,7 +538,7 @@ mod stdlib_tests { let string_stdlib = load_string_stdlib(); let replace_func = string_stdlib.get("replace").expect("Function 'replace' not found in string stdlib"); - assert_eq!(replace_func.kind, Type::TString); + assert_eq!(replace_func.kind, Some(Type::TString)); let params = replace_func.params.as_ref().expect("Expected parameters for replace"); assert_eq!(params.len(), 4); @@ -551,7 +551,7 @@ mod stdlib_tests { assert_eq!(params[3].0, "count"); assert_eq!(params[3].1, Type::TInteger); - match *replace_func.body { + match replace_func.body.as_ref().expect("Expected body for replace").as_ref() { Statement::Return(ref inner) => { match **inner { Expression::MetaExp(_, ref args, ref ret_type) => { diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index eaddbc6..c8f78d0 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; -use crate::ir::ast::{Function, Type, Statement, Expression, EnvValue}; +use crate::ir::ast::{Function, Type, Statement, Expression}; +use crate::interpreter::interpreter::EnvValue; pub fn load_string_stdlib() -> HashMap { let mut string_stdlib = HashMap::new(); @@ -7,104 +8,111 @@ pub fn load_string_stdlib() -> HashMap { string_stdlib.insert( "str_upper".to_string(), Function { - kind: Type::TString, + name: "str_upper".to_string(), + kind: Some(Type::TString), params: Some(vec![("s".to_string(), Type::TString)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( str_upper_impl, vec![Expression::Var("s".to_string())], Type::TString, - )))), + ))))), }, ); string_stdlib.insert( "str_lower".to_string(), Function { - kind: Type::TString, + name: "str_lower".to_string(), + kind: Some(Type::TString), params: Some(vec![("s".to_string(), Type::TString)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( str_lower_impl, vec![Expression::Var("s".to_string())], Type::TString, - )))), + ))))), }, ); string_stdlib.insert( "str_length".to_string(), Function { - kind: Type::TInteger, + name: "str_length".to_string(), + kind: Some(Type::TInteger), params: Some(vec![("s".to_string(), Type::TString)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( str_length_impl, vec![Expression::Var("s".to_string())], Type::TInteger, - )))), + ))))), }, ); string_stdlib.insert( "str_reverse".to_string(), Function { - kind: Type::TString, + name: "str_reverse".to_string(), + kind: Some(Type::TString), params: Some(vec![("s".to_string(), Type::TString)]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( str_reverse_impl, vec![Expression::Var("s".to_string())], Type::TString, - )))), + ))))), }, ); string_stdlib.insert( "cont_chars".to_string(), Function { - kind: Type::TInteger, + name: "cont_chars".to_string(), + kind: Some(Type::TInteger), params: Some(vec![ ("s".to_string(), Type::TString), ("c".to_string(), Type::TString), ]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( cont_chars_impl, vec![ Expression::Var("s".to_string()), Expression::Var("c".to_string()), ], Type::TInteger, - )))), + ))))), }, ); string_stdlib.insert( "filter_out_char".to_string(), Function { - kind: Type::TString, + name: "filter_out_char".to_string(), + kind: Some(Type::TString), params: Some(vec![ ("s".to_string(), Type::TString), ("c".to_string(), Type::TString), ]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( filter_out_char_impl, vec![ Expression::Var("s".to_string()), Expression::Var("c".to_string()), ], Type::TString, - )))), + ))))), }, ); string_stdlib.insert( "replace".to_string(), Function { - kind: Type::TString, + name: "replace".to_string(), + kind: Some(Type::TString), params: Some(vec![ ("s".to_string(), Type::TString), ("old".to_string(), Type::TString), ("new".to_string(), Type::TString), ("count".to_string(), Type::TInteger), ]), - body: Box::new(Statement::Return(Box::new(Expression::MetaExp( + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( replace_impl, vec![ Expression::Var("s".to_string()), @@ -113,7 +121,7 @@ pub fn load_string_stdlib() -> HashMap { Expression::Var("count".to_string()), ], Type::TString, - )))), + ))))), }, ); diff --git a/src/tc/type_checker.rs b/src/tc/type_checker.rs index 13b81d0..ee740d5 100644 --- a/src/tc/type_checker.rs +++ b/src/tc/type_checker.rs @@ -11,6 +11,7 @@ pub fn check_exp(exp: Expression, env: &Environment) -> Result Ok(Type::TBool), Expression::CFalse => Ok(Type::TBool), + Expression::CVoid => Ok(Type::TVoid), Expression::CInt(_) => Ok(Type::TInteger), Expression::CReal(_) => Ok(Type::TReal), Expression::CString(_) => Ok(Type::TString), @@ -27,8 +28,18 @@ pub fn check_exp(exp: Expression, env: &Environment) -> Result check_bin_relational_expression(*l, *r, env), Expression::LTE(l, r) => check_bin_relational_expression(*l, *r, env), Expression::Var(name) => check_var_name(name, env, false), + + Expression::COk(e) => check_result_ok(*e, env), + Expression::CErr(e) => check_result_err(*e, env), + Expression::CJust(e) => check_maybe_just(*e, env), + Expression::CNothing => Ok(Type::TMaybe(Box::new(Type::TAny))), + Expression::IsError(e) => check_iserror_type(*e, env), + Expression::IsNothing(e) => check_isnothing_type(*e, env), + Expression::Unwrap(e) => check_unwrap_type(*e, env), + Expression::Propagate(e) => check_propagate_type(*e, env), Expression::FuncCall(name, args) => check_func_call(name, args, env), Expression::MetaExp(_, args, return_type) => check_metaexp(args, return_type, env), + //_ => Err(String::from("not implemented yet")), } } @@ -297,10 +308,67 @@ fn check_bin_relational_expression( } } +fn check_result_ok(exp: Expression, env: &Environment) -> Result { + let exp_type = check_exp(exp, env)?; + return Ok(Type::TResult(Box::new(exp_type), Box::new(Type::TAny))); +} + +fn check_result_err(exp: Expression, env: &Environment) -> Result { + let exp_type = check_exp(exp, env)?; + return Ok(Type::TResult(Box::new(Type::TAny), Box::new(exp_type))); +} + +fn check_unwrap_type(exp: Expression, env: &Environment) -> Result { + let exp_type = check_exp(exp, env)?; + + match exp_type { + Type::TMaybe(t) => Ok(*t), + Type::TResult(tl, _) => Ok(*tl), + _ => Err(String::from( + "[Type Error] expecting a maybe or result type value.", + )), + } +} + +fn check_propagate_type(exp: Expression, env: &Environment) -> Result { + let exp_type = check_exp(exp, env)?; + + match exp_type { + Type::TMaybe(t) => Ok(*t), + Type::TResult(tl, _) => Ok(*tl), + _ => Err(String::from( + "[Type Error] expecting a maybe or result type value.", + )), + } +} + +fn check_maybe_just(exp: Expression, env: &Environment) -> Result { + let exp_type = check_exp(exp, env)?; + Ok(Type::TMaybe(Box::new(exp_type))) +} + +fn check_iserror_type(exp: Expression, env: &Environment) -> Result { + let v = check_exp(exp, env)?; + + match v { + Type::TResult(_, _) => Ok(Type::TBool), + _ => Err(String::from("[Type Error] expecting a result type value.")), + } +} + +fn check_isnothing_type(exp: Expression, env: &Environment) -> Result { + let exp_type = check_exp(exp, env)?; + + match exp_type { + Type::TMaybe(_) => Ok(Type::TBool), + _ => Err(String::from("[Type Error] expecting a maybe type value.")), + } +} + fn check_metaexp( args: Vec, return_type: Type, - env: &Environment, + env: &Environment, ) -> Result { for arg in args { check_exp(arg.clone(), env)?; @@ -318,7 +386,7 @@ mod tests { use crate::ir::ast::Statement::*; use crate::ir::ast::Type::*; use crate::stdlib::math::sqrt_impl; - + #[test] fn check_tlist_comparison() { let t_list1 = TList(Box::new(TInteger)); @@ -459,6 +527,158 @@ mod tests { ); } + #[test] + fn check_ok_result() { + let env = Environment::new(); + let f10 = CReal(10.0); + let ok = COk(Box::new(f10)); + + assert_eq!( + check_exp(ok, &env), + Ok(TResult(Box::new(TReal), Box::new(TAny))) + ); + } + + #[test] + fn check_err_result() { + let env = Environment::new(); + let ecode = CInt(1); + let err = CErr(Box::new(ecode)); + + assert_eq!( + check_exp(err, &env), + Ok(TResult(Box::new(TAny), Box::new(TInteger))) + ); + } + + #[test] + fn check_just_integer() { + let env = Environment::new(); + let c5 = CInt(5); + let just = CJust(Box::new(c5)); + + assert_eq!(check_exp(just, &env), Ok(TMaybe(Box::new(TInteger)))) + } + + #[test] + fn check_is_error_result_positive() { + let env = Environment::new(); + let bool = CTrue; + let ok = COk(Box::new(bool)); + let ie = IsError(Box::new(ok)); + + assert_eq!(check_exp(ie, &env), Ok(TBool)); + } + + #[test] + fn check_is_error_result_error() { + let env = Environment::new(); + let bool = CTrue; + let ie = IsError(Box::new(bool)); + + assert_eq!( + check_exp(ie, &env), + Err(String::from("[Type Error] expecting a result type value.")) + ); + } + + #[test] + fn check_nothing() { + let env = Environment::new(); + + assert_eq!(check_exp(CNothing, &env), Ok(TMaybe(Box::new(TAny)))); + } + + #[test] + fn check_is_nothing_on_maybe() { + let env = Environment::new(); + let c5 = CInt(5); + let just = CJust(Box::new(c5)); + let is_nothing = IsNothing(Box::new(just)); + + assert_eq!(check_exp(is_nothing, &env), Ok(TBool)); + } + + #[test] + fn check_is_nothing_type_error() { + let env = Environment::new(); + let c5 = CInt(5); + let is_nothing = IsNothing(Box::new(c5)); + + assert_eq!( + check_exp(is_nothing, &env), + Err(String::from("[Type Error] expecting a maybe type value.")) + ); + } + + #[test] + fn check_unwrap_maybe() { + let env = Environment::new(); + let c5 = CInt(5); + let some = CJust(Box::new(c5)); + let u = Unwrap(Box::new(some)); + + assert_eq!(check_exp(u, &env), Ok(TInteger)); + } + + #[test] + fn check_unwrap_maybe_type_error() { + let env = Environment::new(); + let c5 = CInt(5); + let u = Unwrap(Box::new(c5)); + + assert_eq!( + check_exp(u, &env), + Err(String::from( + "[Type Error] expecting a maybe or result type value." + )) + ); + } + + #[test] + fn check_unwrap_result() { + let env = Environment::new(); + let bool = CTrue; + let ok = COk(Box::new(bool)); + let u = Unwrap(Box::new(ok)); + + assert_eq!(check_exp(u, &env), Ok(TBool)); + } + + #[test] + fn check_propagate_maybe() { + let env = Environment::new(); + let c5 = CInt(5); + let some = CJust(Box::new(c5)); + let u = Propagate(Box::new(some)); + + assert_eq!(check_exp(u, &env), Ok(TInteger)); + } + + #[test] + fn check_propagate_maybe_type_error() { + let env = Environment::new(); + let c5 = CInt(5); + let u = Propagate(Box::new(c5)); + + assert_eq!( + check_exp(u, &env), + Err(String::from( + "[Type Error] expecting a maybe or result type value." + )) + ); + } + + #[test] + fn check_propagate_result() { + let env = Environment::new(); + let bool = CTrue; + let ok = COk(Box::new(bool)); + let u = Propagate(Box::new(ok)); + + assert_eq!(check_exp(u, &env), Ok(TBool)); + } + #[test] fn check_assignment() { let env: Environment = Environment::new(); @@ -861,22 +1081,19 @@ mod tests { Err(msg) => assert_eq!(msg, "[Parameter Error] Duplicate parameter name 'x'"), } } - + #[test] - fn check_metaexp_sqrt_impl() { - let mut env = HashMap::new(); - env.insert( - "x".to_string(), - (Some(EnvValue::Exp(Expression::CReal(25.0))), Type::TReal), - ); - + fn check_metaexp_sqrt() { + let mut env = Environment::::new(); + env.insert_variable("x".to_string(), Type::TReal); + let meta_expr = Expression::MetaExp( sqrt_impl, vec![Expression::Var("x".to_string())], Type::TReal, ); - - let ty = check_exp(meta_expr, &env).expect("Type checking failed"); - assert_eq!(ty, Type::TReal); + + let result_type = check_exp(meta_expr, &env).expect("Type checking failed"); + assert_eq!(result_type, Type::TReal); } -} +} \ No newline at end of file From d164e4a66ace0c8e2adf8c911bdbfa3539a74ad0 Mon Sep 17 00:00:00 2001 From: Rafael Cordeiro Date: Tue, 25 Feb 2025 19:11:24 -0300 Subject: [PATCH 15/15] aplicado cargo fmt --- src/interpreter/interpreter.rs | 14 +- src/ir/ast.rs | 8 +- src/main.rs | 4 +- src/parser/parser.rs | 2 +- src/stdlib.rs | 2 +- src/stdlib/math.rs | 332 +++++++++++------- src/stdlib/stdlib.rs | 622 +++++++++++++++++++++------------ src/stdlib/string.rs | 54 ++- src/tc/type_checker.rs | 8 +- 9 files changed, 664 insertions(+), 382 deletions(-) diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index ac416f7..6f29e3a 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -834,7 +834,7 @@ fn meta( args_values.push(value); } let result_value = f(args_values).map_err(|s| (s, None))?; - + Ok(result_value) } @@ -2182,18 +2182,20 @@ mod tests { fn interpreter_metaexp_sqrt_returns_correct_value() { let mut env = Environment::::new(); env.insert_variable("x".to_string(), EnvValue::Exp(Expression::CReal(25.0))); - + let meta_expr = Expression::MetaExp( sqrt_impl, vec![Expression::Var("x".to_string())], Type::TReal, ); - + let result_value = eval(meta_expr, &env).expect("Evaluation failed"); - + match result_value { - EnvValue::Exp(Expression::CReal(v)) => assert!((v - 5.0).abs() < 0.0001, "Expected 5.0, got {}", v), + EnvValue::Exp(Expression::CReal(v)) => { + assert!((v - 5.0).abs() < 0.0001, "Expected 5.0, got {}", v) + } _ => panic!("Expected a CReal result"), } } -} \ No newline at end of file +} diff --git a/src/ir/ast.rs b/src/ir/ast.rs index 659bcba..4797dd0 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -166,7 +166,11 @@ pub enum Expression { /* function call */ FuncCall(Name, Vec), - MetaExp(fn(Vec) -> Result, Vec, Type), + MetaExp( + fn(Vec) -> Result, + Vec, + Type, + ), /* arithmetic expressions over numbers */ Add(Box, Box), @@ -234,4 +238,4 @@ pub fn with_error_context<'a, T>( parser(input) .map_err(|_| nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Tag))) } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index a794b6f..0600bf5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,8 +13,8 @@ use std::io::Write;*/ pub mod interpreter; pub mod ir; pub mod parser; -pub mod tc; pub mod stdlib; +pub mod tc; fn main() { println!("Hello, world!"); @@ -683,4 +683,4 @@ result4 = (x >= y) and (not False)"#; // Also print to console print!("{}", all_results); } - */ */ \ No newline at end of file + */ */ diff --git a/src/parser/parser.rs b/src/parser/parser.rs index f546b10..dfa7d3b 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1356,4 +1356,4 @@ mod tests { assert!(result.is_err()); } -} \ No newline at end of file +} diff --git a/src/stdlib.rs b/src/stdlib.rs index 2d5d6e4..5e71e19 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -1,3 +1,3 @@ pub mod math; +pub mod stdlib; pub mod string; -pub mod stdlib; \ No newline at end of file diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs index cd61489..d15454f 100644 --- a/src/stdlib/math.rs +++ b/src/stdlib/math.rs @@ -1,6 +1,6 @@ -use std::collections::HashMap; -use crate::ir::ast::{Expression, Function, Statement, Type}; use crate::interpreter::interpreter::EnvValue; +use crate::ir::ast::{Expression, Function, Statement, Type}; +use std::collections::HashMap; pub fn load_math_stdlib() -> HashMap { let mut math_stdlib = HashMap::new(); @@ -11,18 +11,26 @@ pub fn load_math_stdlib() -> HashMap { name: "sqrt".to_string(), kind: Some(Type::TReal), params: Some(vec![("x".to_string(), Type::TReal)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(sqrt_impl, vec![Expression::Var("x".to_string())], Type::TReal))))), - } + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + sqrt_impl, + vec![Expression::Var("x".to_string())], + Type::TReal, + ))))), + }, ); - + math_stdlib.insert( "factorial".to_string(), Function { name: "factorial".to_string(), kind: Some(Type::TInteger), params: Some(vec![("n".to_string(), Type::TInteger)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(factorial_impl, vec![Expression::Var("x".to_string())], Type::TInteger))))), - } + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + factorial_impl, + vec![Expression::Var("x".to_string())], + Type::TInteger, + ))))), + }, ); math_stdlib.insert( @@ -30,9 +38,19 @@ pub fn load_math_stdlib() -> HashMap { Function { name: "gcd".to_string(), kind: Some(Type::TInteger), - params: Some(vec![("a".to_string(), Type::TInteger), ("b".to_string(), Type::TInteger)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(gcd_impl, vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], Type::TInteger))))), - } + params: Some(vec![ + ("a".to_string(), Type::TInteger), + ("b".to_string(), Type::TInteger), + ]), + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + gcd_impl, + vec![ + Expression::Var("a".to_string()), + Expression::Var("b".to_string()), + ], + Type::TInteger, + ))))), + }, ); math_stdlib.insert( @@ -40,9 +58,19 @@ pub fn load_math_stdlib() -> HashMap { Function { name: "lcm".to_string(), kind: Some(Type::TInteger), - params: Some(vec![("a".to_string(), Type::TInteger), ("b".to_string(), Type::TInteger)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(lcm_impl, vec![Expression::Var("a".to_string()), Expression::Var("b".to_string())], Type::TInteger))))), - } + params: Some(vec![ + ("a".to_string(), Type::TInteger), + ("b".to_string(), Type::TInteger), + ]), + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + lcm_impl, + vec![ + Expression::Var("a".to_string()), + Expression::Var("b".to_string()), + ], + Type::TInteger, + ))))), + }, ); math_stdlib.insert( @@ -51,28 +79,52 @@ pub fn load_math_stdlib() -> HashMap { name: "is_prime".to_string(), kind: Some(Type::TBool), params: Some(vec![("x".to_string(), Type::TInteger)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(is_prime_impl, vec![Expression::Var("x".to_string())], Type::TBool))))), - } + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + is_prime_impl, + vec![Expression::Var("x".to_string())], + Type::TBool, + ))))), + }, ); math_stdlib.insert( - "comb".to_string(), + "comb".to_string(), Function { name: "comb".to_string(), kind: Some(Type::TInteger), - params: Some(vec![("n".to_string(), Type::TInteger), ("k".to_string(), Type::TInteger)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(comb_impl, vec![Expression::Var("n".to_string()), Expression::Var("r".to_string())], Type::TInteger))))) - } + params: Some(vec![ + ("n".to_string(), Type::TInteger), + ("k".to_string(), Type::TInteger), + ]), + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + comb_impl, + vec![ + Expression::Var("n".to_string()), + Expression::Var("r".to_string()), + ], + Type::TInteger, + ))))), + }, ); math_stdlib.insert( - "perm".to_string(), + "perm".to_string(), Function { name: "perm".to_string(), kind: Some(Type::TInteger), - params: Some(vec![("n".to_string(), Type::TInteger), ("k".to_string(), Type::TInteger)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(perm_impl, vec![Expression::Var("n".to_string()), Expression::Var("r".to_string())], Type::TInteger))))) - } + params: Some(vec![ + ("n".to_string(), Type::TInteger), + ("k".to_string(), Type::TInteger), + ]), + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + perm_impl, + vec![ + Expression::Var("n".to_string()), + Expression::Var("r".to_string()), + ], + Type::TInteger, + ))))), + }, ); math_stdlib.insert( @@ -80,9 +132,19 @@ pub fn load_math_stdlib() -> HashMap { Function { name: "log".to_string(), kind: Some(Type::TReal), - params: Some(vec![("x".to_string(), Type::TReal), ("base".to_string(), Type::TReal)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(log_impl, vec![Expression::Var("x".to_string()), Expression::Var("base".to_string())], Type::TReal))))) - } + params: Some(vec![ + ("x".to_string(), Type::TReal), + ("base".to_string(), Type::TReal), + ]), + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + log_impl, + vec![ + Expression::Var("x".to_string()), + Expression::Var("base".to_string()), + ], + Type::TReal, + ))))), + }, ); math_stdlib.insert( @@ -91,9 +153,13 @@ pub fn load_math_stdlib() -> HashMap { name: "degrees".to_string(), kind: Some(Type::TReal), params: Some(vec![("rad".to_string(), Type::TReal)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(degrees_impl, vec![Expression::Var("rad".to_string())], Type::TReal))))) - } - ); + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + degrees_impl, + vec![Expression::Var("rad".to_string())], + Type::TReal, + ))))), + }, + ); math_stdlib.insert( "radians".to_string(), @@ -101,8 +167,12 @@ pub fn load_math_stdlib() -> HashMap { name: "radians".to_string(), kind: Some(Type::TReal), params: Some(vec![("deg".to_string(), Type::TReal)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(radians_impl, vec![Expression::Var("deg".to_string())], Type::TReal))))) - } + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + radians_impl, + vec![Expression::Var("deg".to_string())], + Type::TReal, + ))))), + }, ); math_stdlib.insert( @@ -111,8 +181,12 @@ pub fn load_math_stdlib() -> HashMap { name: "cos".to_string(), kind: Some(Type::TReal), params: Some(vec![("x".to_string(), Type::TReal)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(cos_impl, vec![Expression::Var("x".to_string())], Type::TReal))))) - } + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + cos_impl, + vec![Expression::Var("x".to_string())], + Type::TReal, + ))))), + }, ); math_stdlib.insert( @@ -121,8 +195,12 @@ pub fn load_math_stdlib() -> HashMap { name: "sin".to_string(), kind: Some(Type::TReal), params: Some(vec![("x".to_string(), Type::TReal)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(sin_impl, vec![Expression::Var("x".to_string())], Type::TReal))))) - } + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + sin_impl, + vec![Expression::Var("x".to_string())], + Type::TReal, + ))))), + }, ); math_stdlib.insert( @@ -131,8 +209,12 @@ pub fn load_math_stdlib() -> HashMap { name: "tan".to_string(), kind: Some(Type::TReal), params: Some(vec![("x".to_string(), Type::TReal)]), - body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp(tan_impl, vec![Expression::Var("x".to_string())], Type::TReal))))) - } + body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( + tan_impl, + vec![Expression::Var("x".to_string())], + Type::TReal, + ))))), + }, ); math_stdlib @@ -190,7 +272,6 @@ pub fn gcd_impl(args: Vec) -> Result { } } - pub fn lcm_impl(args: Vec) -> Result { if args.len() != 2 { return Err("lcm expects exactly two arguments".to_string()); @@ -217,7 +298,9 @@ pub fn comb_impl(args: Vec) -> Result { return Err("comb expects exactly two arguments".to_string()); } - if let (EnvValue::Exp(Expression::CInt(n)), EnvValue::Exp(Expression::CInt(k))) = (&args[0], &args[1]) { + if let (EnvValue::Exp(Expression::CInt(n)), EnvValue::Exp(Expression::CInt(k))) = + (&args[0], &args[1]) + { if *n < 0 || *k < 0 { return Err("comb expects non-negative integers".to_string()); } @@ -241,7 +324,9 @@ pub fn perm_impl(args: Vec) -> Result { return Err("perm expects exactly two arguments".to_string()); } - if let (EnvValue::Exp(Expression::CInt(n)), EnvValue::Exp(Expression::CInt(k))) = (&args[0], &args[1]) { + if let (EnvValue::Exp(Expression::CInt(n)), EnvValue::Exp(Expression::CInt(k))) = + (&args[0], &args[1]) + { if *n < 0 || *k < 0 { return Err("perm expects non-negative integers".to_string()); } @@ -300,7 +385,6 @@ pub fn is_prime_impl(args: Vec) -> Result { } } - pub fn log_impl(args: Vec) -> Result { if args.len() != 2 { return Err("log expects exactly two arguments".to_string()); @@ -429,7 +513,7 @@ pub fn tan_impl(args: Vec) -> Result { mod tests { use super::*; -//TESTES FUNCAO SQRT + //TESTES FUNCAO SQRT #[test] fn test_sqrt_positive_real() { let result = sqrt_impl(vec![EnvValue::Exp(Expression::CReal(9.0))]); @@ -483,7 +567,7 @@ mod tests { assert!(result.is_err()); assert_eq!(result.unwrap_err(), "sqrt expects a real number argument"); } -//TESTES FUNCAO FACTORIAL + //TESTES FUNCAO FACTORIAL #[test] fn test_factorial_valid_inputs() { let result = factorial_impl(vec![EnvValue::Exp(Expression::CInt(0))]); @@ -515,7 +599,10 @@ mod tests { fn test_factorial_invalid_number_of_arguments() { let result = factorial_impl(vec![]); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), "factorial expects exactly one argument"); + assert_eq!( + result.unwrap_err(), + "factorial expects exactly one argument" + ); } #[test] @@ -525,7 +612,10 @@ mod tests { EnvValue::Exp(Expression::CInt(2)), ]); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), "factorial expects exactly one argument"); + assert_eq!( + result.unwrap_err(), + "factorial expects exactly one argument" + ); } #[test] @@ -539,9 +629,12 @@ mod tests { fn test_factorial_negative_argument() { let result = factorial_impl(vec![EnvValue::Exp(Expression::CInt(-1))]); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), "factorial expects a non-negative integer argument"); + assert_eq!( + result.unwrap_err(), + "factorial expects a non-negative integer argument" + ); } -//TESTES FUNCAO GCD + //TESTES FUNCAO GCD #[test] fn test_gcd_valid_inputs() { let result = gcd_impl(vec![ @@ -608,7 +701,7 @@ mod tests { assert!(result.is_err()); assert_eq!(result.unwrap_err(), "gcd expects two integer arguments"); } -//TESTES PARA LCM + //TESTES PARA LCM #[test] fn test_lcm_valid_inputs() { let result = lcm_impl(vec![ @@ -676,7 +769,7 @@ mod tests { assert_eq!(result.unwrap_err(), "lcm expects two integer arguments"); } -//TESTES PARA COMB + //TESTES PARA COMB #[test] fn test_comb_valid_inputs() { let result = comb_impl(vec![ @@ -745,7 +838,7 @@ mod tests { assert_eq!(result.unwrap_err(), "comb expects non-negative integers"); } -//TESTES PARA PERM + //TESTES PARA PERM #[test] fn test_perm_valid_inputs() { let result = perm_impl(vec![ @@ -814,7 +907,7 @@ mod tests { assert_eq!(result.unwrap_err(), "perm expects non-negative integers"); } -//================================================================================================= + //================================================================================================= #[test] fn test_is_prime_valid_inputs() { let result = is_prime_impl(vec![EnvValue::Exp(Expression::CInt(2))]); @@ -876,10 +969,13 @@ mod tests { fn test_is_prime_negative_argument() { let result = is_prime_impl(vec![EnvValue::Exp(Expression::CInt(-1))]); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), "is_prime expects a non-negative integer"); + assert_eq!( + result.unwrap_err(), + "is_prime expects a non-negative integer" + ); } -//================================================================================================= + //================================================================================================= #[test] fn test_log_valid_inputs() { let result = log_impl(vec![ @@ -938,79 +1034,79 @@ mod tests { assert_eq!(result.unwrap_err(), "log expects two real arguments"); } #[test] -fn test_degrees_impl() { - let arg = vec![EnvValue::Exp(Expression::CReal(PI))]; - let result = degrees_impl(arg).unwrap(); - if let EnvValue::Exp(Expression::CReal(deg)) = result { - assert!((deg - 180.0).abs() < EPSILON); - } else { - panic!("Unexpected result type"); + fn test_degrees_impl() { + let arg = vec![EnvValue::Exp(Expression::CReal(PI))]; + let result = degrees_impl(arg).unwrap(); + if let EnvValue::Exp(Expression::CReal(deg)) = result { + assert!((deg - 180.0).abs() < EPSILON); + } else { + panic!("Unexpected result type"); + } } -} -#[test] -fn test_radians_impl() { - let arg = vec![EnvValue::Exp(Expression::CReal(180.0))]; - let result = radians_impl(arg).unwrap(); - if let EnvValue::Exp(Expression::CReal(rad)) = result { - assert!((rad - PI).abs() < EPSILON); - } else { - panic!("Unexpected result type"); + #[test] + fn test_radians_impl() { + let arg = vec![EnvValue::Exp(Expression::CReal(180.0))]; + let result = radians_impl(arg).unwrap(); + if let EnvValue::Exp(Expression::CReal(rad)) = result { + assert!((rad - PI).abs() < EPSILON); + } else { + panic!("Unexpected result type"); + } } -} -#[test] -fn test_cos_impl() { - let arg = vec![EnvValue::Exp(Expression::CReal(0.0))]; - let result = cos_impl(arg).unwrap(); - if let EnvValue::Exp(Expression::CReal(value)) = result { - assert!((value - 1.0).abs() < EPSILON); - } else { - panic!("Unexpected result type"); + #[test] + fn test_cos_impl() { + let arg = vec![EnvValue::Exp(Expression::CReal(0.0))]; + let result = cos_impl(arg).unwrap(); + if let EnvValue::Exp(Expression::CReal(value)) = result { + assert!((value - 1.0).abs() < EPSILON); + } else { + panic!("Unexpected result type"); + } } -} -#[test] -fn test_sin_impl() { - let arg = vec![EnvValue::Exp(Expression::CReal(0.0))]; - let result = sin_impl(arg).unwrap(); - if let EnvValue::Exp(Expression::CReal(value)) = result { - assert!(value.abs() < EPSILON); - } else { - panic!("Unexpected result type"); + #[test] + fn test_sin_impl() { + let arg = vec![EnvValue::Exp(Expression::CReal(0.0))]; + let result = sin_impl(arg).unwrap(); + if let EnvValue::Exp(Expression::CReal(value)) = result { + assert!(value.abs() < EPSILON); + } else { + panic!("Unexpected result type"); + } } -} -#[test] -fn test_tan_impl() { - let arg = vec![EnvValue::Exp(Expression::CReal(0.0))]; - let result = tan_impl(arg).unwrap(); - if let EnvValue::Exp(Expression::CReal(value)) = result { - assert!(value.abs() < EPSILON); - } else { - panic!("Unexpected result type"); + #[test] + fn test_tan_impl() { + let arg = vec![EnvValue::Exp(Expression::CReal(0.0))]; + let result = tan_impl(arg).unwrap(); + if let EnvValue::Exp(Expression::CReal(value)) = result { + assert!(value.abs() < EPSILON); + } else { + panic!("Unexpected result type"); + } } -} -#[test] -fn test_invalid_args() { - // Teste com número errado de argumentos - let too_many_args = vec![ - EnvValue::Exp(Expression::CReal(1.0)), - EnvValue::Exp(Expression::CReal(2.0)) - ]; - assert!(degrees_impl(too_many_args.clone()).is_err()); - assert!(radians_impl(too_many_args.clone()).is_err()); - assert!(cos_impl(too_many_args.clone()).is_err()); - assert!(sin_impl(too_many_args.clone()).is_err()); - assert!(tan_impl(too_many_args.clone()).is_err()); - - // Teste com tipo errado de argumento - let invalid_type_arg = vec![EnvValue::Exp(Expression::CString("invalid".to_string()))]; - assert!(degrees_impl(invalid_type_arg.clone()).is_err()); - assert!(radians_impl(invalid_type_arg.clone()).is_err()); - assert!(cos_impl(invalid_type_arg.clone()).is_err()); - assert!(sin_impl(invalid_type_arg.clone()).is_err()); - assert!(tan_impl(invalid_type_arg.clone()).is_err()); + #[test] + fn test_invalid_args() { + // Teste com número errado de argumentos + let too_many_args = vec![ + EnvValue::Exp(Expression::CReal(1.0)), + EnvValue::Exp(Expression::CReal(2.0)), + ]; + assert!(degrees_impl(too_many_args.clone()).is_err()); + assert!(radians_impl(too_many_args.clone()).is_err()); + assert!(cos_impl(too_many_args.clone()).is_err()); + assert!(sin_impl(too_many_args.clone()).is_err()); + assert!(tan_impl(too_many_args.clone()).is_err()); + + // Teste com tipo errado de argumento + let invalid_type_arg = vec![EnvValue::Exp(Expression::CString("invalid".to_string()))]; + assert!(degrees_impl(invalid_type_arg.clone()).is_err()); + assert!(radians_impl(invalid_type_arg.clone()).is_err()); + assert!(cos_impl(invalid_type_arg.clone()).is_err()); + assert!(sin_impl(invalid_type_arg.clone()).is_err()); + assert!(tan_impl(invalid_type_arg.clone()).is_err()); + } } -} \ No newline at end of file diff --git a/src/stdlib/stdlib.rs b/src/stdlib/stdlib.rs index 98d768a..0343283 100644 --- a/src/stdlib/stdlib.rs +++ b/src/stdlib/stdlib.rs @@ -1,5 +1,5 @@ -use std::collections::HashMap; use crate::ir::ast::Function; +use std::collections::HashMap; use crate::stdlib::math::load_math_stdlib; use crate::stdlib::string::load_string_stdlib; @@ -22,275 +22,355 @@ pub fn load_stdlib() -> HashMap { #[cfg(test)] mod tests { - use crate::ir::ast::{Statement, Expression, Type}; + use crate::ir::ast::{Expression, Statement, Type}; use crate::stdlib::math::load_math_stdlib; use crate::stdlib::string::load_string_stdlib; #[test] fn test_load_math_stdlib_contains_sqrt() { let math_stdlib = load_math_stdlib(); - let sqrt_func = math_stdlib.get("sqrt").expect("Function 'sqrt' not found in math stdlib"); + let sqrt_func = math_stdlib + .get("sqrt") + .expect("Function 'sqrt' not found in math stdlib"); assert_eq!(sqrt_func.kind, Some(Type::TReal)); - let params = sqrt_func.params.as_ref().expect("Expected parameters for sqrt"); + let params = sqrt_func + .params + .as_ref() + .expect("Expected parameters for sqrt"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TReal); - match sqrt_func.body.as_ref().expect("Expected body for sqrt").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TReal); - }, - _ => panic!("Expected MetaExp inside Return for sqrt"), + match sqrt_func + .body + .as_ref() + .expect("Expected body for sqrt") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); } + _ => panic!("Expected MetaExp inside Return for sqrt"), }, _ => panic!("Expected Return statement for sqrt body"), } } #[test] - fn test_load_math_stdlib_contains_factorial(){ + fn test_load_math_stdlib_contains_factorial() { let math_stdlib = load_math_stdlib(); - let factorial_func = math_stdlib.get("factorial").expect("Function 'factorial' not found in math stdlib"); + let factorial_func = math_stdlib + .get("factorial") + .expect("Function 'factorial' not found in math stdlib"); assert_eq!(factorial_func.kind, Some(Type::TInteger)); - let params = factorial_func.params.as_ref().expect("Expected parameters for factorial"); + let params = factorial_func + .params + .as_ref() + .expect("Expected parameters for factorial"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "n"); assert_eq!(params[0].1, Type::TInteger); - match factorial_func.body.as_ref().expect("Expected body for factorial").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TInteger); - }, - _ => panic!("Expected MetaExp inside Return for factorial"), + match factorial_func + .body + .as_ref() + .expect("Expected body for factorial") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TInteger); } + _ => panic!("Expected MetaExp inside Return for factorial"), }, _ => panic!("Expected Return statement for factorial body"), } } #[test] - fn test_load_math_stdlib_contains_gcd(){ + fn test_load_math_stdlib_contains_gcd() { let math_stdlib = load_math_stdlib(); - let gcd_func = math_stdlib.get("gcd").expect("Function 'gcd' not found in math stdlib"); + let gcd_func = math_stdlib + .get("gcd") + .expect("Function 'gcd' not found in math stdlib"); assert_eq!(gcd_func.kind, Some(Type::TInteger)); - let params = gcd_func.params.as_ref().expect("Expected parameters for gcd"); + let params = gcd_func + .params + .as_ref() + .expect("Expected parameters for gcd"); assert_eq!(params.len(), 2); assert_eq!(params[0].0, "a"); assert_eq!(params[0].1, Type::TInteger); assert_eq!(params[1].0, "b"); assert_eq!(params[1].1, Type::TInteger); - match gcd_func.body.as_ref().expect("Expected body for gcd").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 2); - assert_eq!(*ret_type, Type::TInteger); - }, - _ => panic!("Expected MetaExp inside Return for gcd"), + match gcd_func + .body + .as_ref() + .expect("Expected body for gcd") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TInteger); } + _ => panic!("Expected MetaExp inside Return for gcd"), }, _ => panic!("Expected Return statement for gcd body"), } } #[test] - fn test_load_math_stdlib_contains_lcm(){ + fn test_load_math_stdlib_contains_lcm() { let math_stdlib = load_math_stdlib(); - let lcm_func = math_stdlib.get("lcm").expect("Function 'lcm' not found in math stdlib"); + let lcm_func = math_stdlib + .get("lcm") + .expect("Function 'lcm' not found in math stdlib"); assert_eq!(lcm_func.kind, Some(Type::TInteger)); - let params = lcm_func.params.as_ref().expect("Expected parameters for lcm"); + let params = lcm_func + .params + .as_ref() + .expect("Expected parameters for lcm"); assert_eq!(params.len(), 2); assert_eq!(params[0].0, "a"); assert_eq!(params[0].1, Type::TInteger); assert_eq!(params[1].0, "b"); assert_eq!(params[1].1, Type::TInteger); - match lcm_func.body.as_ref().expect("Expected body for lcm").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 2); - assert_eq!(*ret_type, Type::TInteger); - }, - _ => panic!("Expected MetaExp inside Return for lcm"), + match lcm_func + .body + .as_ref() + .expect("Expected body for lcm") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TInteger); } + _ => panic!("Expected MetaExp inside Return for lcm"), }, _ => panic!("Expected Return statement for lcm body"), } } #[test] - fn test_load_math_stdlib_contains_comb(){ + fn test_load_math_stdlib_contains_comb() { let math_stdlib = load_math_stdlib(); - let comb_func = math_stdlib.get("comb").expect("Function 'comb' not found in math stdlib"); + let comb_func = math_stdlib + .get("comb") + .expect("Function 'comb' not found in math stdlib"); assert_eq!(comb_func.kind, Some(Type::TInteger)); - let params = comb_func.params.as_ref().expect("Expected parameters for comb"); + let params = comb_func + .params + .as_ref() + .expect("Expected parameters for comb"); assert_eq!(params.len(), 2); assert_eq!(params[0].0, "n"); assert_eq!(params[0].1, Type::TInteger); assert_eq!(params[1].0, "k"); assert_eq!(params[1].1, Type::TInteger); - match comb_func.body.as_ref().expect("Expected body for comb").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 2); - assert_eq!(*ret_type, Type::TInteger); - }, - _ => panic!("Expected MetaExp inside Return for comb"), + match comb_func + .body + .as_ref() + .expect("Expected body for comb") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TInteger); } + _ => panic!("Expected MetaExp inside Return for comb"), }, _ => panic!("Expected Return statement for comb body"), } } #[test] - fn test_load_math_stdlib_contains_perm(){ + fn test_load_math_stdlib_contains_perm() { let math_stdlib = load_math_stdlib(); - let perm_func = math_stdlib.get("perm").expect("Function 'perm' not found in math stdlib"); + let perm_func = math_stdlib + .get("perm") + .expect("Function 'perm' not found in math stdlib"); assert_eq!(perm_func.kind, Some(Type::TInteger)); - let params = perm_func.params.as_ref().expect("Expected parameters for perm"); + let params = perm_func + .params + .as_ref() + .expect("Expected parameters for perm"); assert_eq!(params.len(), 2); assert_eq!(params[0].0, "n"); assert_eq!(params[0].1, Type::TInteger); assert_eq!(params[1].0, "k"); assert_eq!(params[1].1, Type::TInteger); - match perm_func.body.as_ref().expect("Expected body for perm").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 2); - assert_eq!(*ret_type, Type::TInteger); - }, - _ => panic!("Expected MetaExp inside Return for perm"), + match perm_func + .body + .as_ref() + .expect("Expected body for perm") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TInteger); } + _ => panic!("Expected MetaExp inside Return for perm"), }, _ => panic!("Expected Return statement for perm body"), } } #[test] - fn test_load_math_stdlib_contains_is_prime(){ + fn test_load_math_stdlib_contains_is_prime() { let math_stdlib = load_math_stdlib(); - let is_prime_func = math_stdlib.get("is_prime").expect("Function 'is_prime' not found in math stdlib"); + let is_prime_func = math_stdlib + .get("is_prime") + .expect("Function 'is_prime' not found in math stdlib"); assert_eq!(is_prime_func.kind, Some(Type::TBool)); - let params = is_prime_func.params.as_ref().expect("Expected parameters for is_prime"); + let params = is_prime_func + .params + .as_ref() + .expect("Expected parameters for is_prime"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TInteger); - match is_prime_func.body.as_ref().expect("Expected body for is_prime").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TBool); - }, - _ => panic!("Expected MetaExp inside Return for is_prime"), + match is_prime_func + .body + .as_ref() + .expect("Expected body for is_prime") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TBool); } + _ => panic!("Expected MetaExp inside Return for is_prime"), }, _ => panic!("Expected Return statement for is_prime body"), } } #[test] - fn test_load_math_stdlib_contains_log(){ + fn test_load_math_stdlib_contains_log() { let math_stdlib = load_math_stdlib(); - let log_func = math_stdlib.get("log").expect("Function 'log' not found in math stdlib"); + let log_func = math_stdlib + .get("log") + .expect("Function 'log' not found in math stdlib"); assert_eq!(log_func.kind, Some(Type::TReal)); - let params = log_func.params.as_ref().expect("Expected parameters for log"); + let params = log_func + .params + .as_ref() + .expect("Expected parameters for log"); assert_eq!(params.len(), 2); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TReal); assert_eq!(params[1].0, "base"); assert_eq!(params[1].1, Type::TReal); - match log_func.body.as_ref().expect("Expected body for log").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 2); - assert_eq!(*ret_type, Type::TReal); - }, - _ => panic!("Expected MetaExp inside Return for log"), + match log_func + .body + .as_ref() + .expect("Expected body for log") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TReal); } + _ => panic!("Expected MetaExp inside Return for log"), }, _ => panic!("Expected Return statement for log body"), } } - + #[test] - fn test_load_math_stdlib_contains_degrees(){ + fn test_load_math_stdlib_contains_degrees() { let math_stdlib = load_math_stdlib(); - let degrees_func = math_stdlib.get("degrees").expect("Function 'degrees' not found in math stdlib"); + let degrees_func = math_stdlib + .get("degrees") + .expect("Function 'degrees' not found in math stdlib"); assert_eq!(degrees_func.kind, Some(Type::TReal)); - let params = degrees_func.params.as_ref().expect("Expected parameters for degrees"); + let params = degrees_func + .params + .as_ref() + .expect("Expected parameters for degrees"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "rad"); assert_eq!(params[0].1, Type::TReal); - match degrees_func.body.as_ref().expect("Expected body for degrees").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TReal); - }, - _ => panic!("Expected MetaExp inside Return for degrees"), + match degrees_func + .body + .as_ref() + .expect("Expected body for degrees") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); } + _ => panic!("Expected MetaExp inside Return for degrees"), }, _ => panic!("Expected Return statement for degrees body"), } } #[test] - fn test_load_math_stdlib_contains_radians(){ + fn test_load_math_stdlib_contains_radians() { let math_stdlib = load_math_stdlib(); - let radians_func = math_stdlib.get("radians").expect("Function 'radians' not found in math stdlib"); + let radians_func = math_stdlib + .get("radians") + .expect("Function 'radians' not found in math stdlib"); assert_eq!(radians_func.kind, Some(Type::TReal)); - let params = radians_func.params.as_ref().expect("Expected parameters for radians"); + let params = radians_func + .params + .as_ref() + .expect("Expected parameters for radians"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "deg"); assert_eq!(params[0].1, Type::TReal); - match radians_func.body.as_ref().expect("Expected body for radians").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TReal); - }, - _ => panic!("Expected MetaExp inside Return for radians"), + match radians_func + .body + .as_ref() + .expect("Expected body for radians") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); } + _ => panic!("Expected MetaExp inside Return for radians"), }, _ => panic!("Expected Return statement for radians body"), } @@ -299,102 +379,134 @@ mod tests { #[test] fn test_load_string_stdlib_contains_str_upper() { let string_stdlib = load_string_stdlib(); - let str_upper_func = string_stdlib.get("str_upper").expect("Function 'str_upper' not found in string stdlib"); - + let str_upper_func = string_stdlib + .get("str_upper") + .expect("Function 'str_upper' not found in string stdlib"); + assert_eq!(str_upper_func.kind, Some(Type::TString)); - - let params = str_upper_func.params.as_ref().expect("Expected parameters for str_upper"); + + let params = str_upper_func + .params + .as_ref() + .expect("Expected parameters for str_upper"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); - - match str_upper_func.body.as_ref().expect("Expected body for str_upper").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TString); - }, - _ => panic!("Expected MetaExp inside Return for str_upper"), + + match str_upper_func + .body + .as_ref() + .expect("Expected body for str_upper") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TString); } + _ => panic!("Expected MetaExp inside Return for str_upper"), }, _ => panic!("Expected Return statement for str_upper body"), } } #[test] - fn test_load_math_stdlib_contains_cos(){ + fn test_load_math_stdlib_contains_cos() { let math_stdlib = load_math_stdlib(); - let cos_func = math_stdlib.get("cos").expect("Function 'cos' not found in math stdlib"); + let cos_func = math_stdlib + .get("cos") + .expect("Function 'cos' not found in math stdlib"); assert_eq!(cos_func.kind, Some(Type::TReal)); - let params = cos_func.params.as_ref().expect("Expected parameters for cos"); + let params = cos_func + .params + .as_ref() + .expect("Expected parameters for cos"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TReal); - match cos_func.body.as_ref().expect("Expected body for cos").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TReal); - }, - _ => panic!("Expected MetaExp inside Return for cos"), + match cos_func + .body + .as_ref() + .expect("Expected body for cos") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); } + _ => panic!("Expected MetaExp inside Return for cos"), }, _ => panic!("Expected Return statement for cos body"), } } - + #[test] - fn test_load_math_stdlib_contains_sin(){ + fn test_load_math_stdlib_contains_sin() { let math_stdlib = load_math_stdlib(); - let sin_func = math_stdlib.get("sin").expect("Function 'sin' not found in math stdlib"); + let sin_func = math_stdlib + .get("sin") + .expect("Function 'sin' not found in math stdlib"); assert_eq!(sin_func.kind, Some(Type::TReal)); - let params = sin_func.params.as_ref().expect("Expected parameters for sin"); + let params = sin_func + .params + .as_ref() + .expect("Expected parameters for sin"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TReal); - match sin_func.body.as_ref().expect("Expected body for sin").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TReal); - }, - _ => panic!("Expected MetaExp inside Return for sin"), + match sin_func + .body + .as_ref() + .expect("Expected body for sin") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); } + _ => panic!("Expected MetaExp inside Return for sin"), }, _ => panic!("Expected Return statement for sin body"), } } - + #[test] - fn test_load_math_stdlib_contains_tan(){ + fn test_load_math_stdlib_contains_tan() { let math_stdlib = load_math_stdlib(); - let tan_func = math_stdlib.get("tan").expect("Function 'tan' not found in math stdlib"); + let tan_func = math_stdlib + .get("tan") + .expect("Function 'tan' not found in math stdlib"); assert_eq!(tan_func.kind, Some(Type::TReal)); - let params = tan_func.params.as_ref().expect("Expected parameters for tan"); + let params = tan_func + .params + .as_ref() + .expect("Expected parameters for tan"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "x"); assert_eq!(params[0].1, Type::TReal); - match tan_func.body.as_ref().expect("Expected body for tan").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TReal); - }, - _ => panic!("Expected MetaExp inside Return for tan"), + match tan_func + .body + .as_ref() + .expect("Expected body for tan") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TReal); } + _ => panic!("Expected MetaExp inside Return for tan"), }, _ => panic!("Expected Return statement for tan body"), } @@ -403,24 +515,32 @@ mod tests { #[test] fn test_load_string_stdlib_contains_str_lower() { let string_stdlib = load_string_stdlib(); - let str_lower_func = string_stdlib.get("str_lower").expect("Function 'str_lower' not found in string stdlib"); + let str_lower_func = string_stdlib + .get("str_lower") + .expect("Function 'str_lower' not found in string stdlib"); assert_eq!(str_lower_func.kind, Some(Type::TString)); - - let params = str_lower_func.params.as_ref().expect("Expected parameters for str_lower"); + + let params = str_lower_func + .params + .as_ref() + .expect("Expected parameters for str_lower"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); - - match str_lower_func.body.as_ref().expect("Expected body for str_lower").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TString); - }, - _ => panic!("Expected MetaExp inside Return for str_lower"), + + match str_lower_func + .body + .as_ref() + .expect("Expected body for str_lower") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TString); } + _ => panic!("Expected MetaExp inside Return for str_lower"), }, _ => panic!("Expected Return statement for str_lower body"), } @@ -428,119 +548,156 @@ mod tests { #[test] fn test_load_string_stdlib_contains_str_length() { let string_stdlib = load_string_stdlib(); - let str_length_func = string_stdlib.get("str_length").expect("Function 'str_length' not found in string stdlib"); - + let str_length_func = string_stdlib + .get("str_length") + .expect("Function 'str_length' not found in string stdlib"); + assert_eq!(str_length_func.kind, Some(Type::TInteger)); - - let params = str_length_func.params.as_ref().expect("Expected parameters for str_length"); + + let params = str_length_func + .params + .as_ref() + .expect("Expected parameters for str_length"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); - - match str_length_func.body.as_ref().expect("Expected body for str_length").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TInteger); - }, - _ => panic!("Expected MetaExp inside Return for str_length"), + + match str_length_func + .body + .as_ref() + .expect("Expected body for str_length") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TInteger); } + _ => panic!("Expected MetaExp inside Return for str_length"), }, _ => panic!("Expected Return statement for str_length body"), } } #[test] - fn test_load_string_stdlib_contains_str_reverse(){ + fn test_load_string_stdlib_contains_str_reverse() { let string_stdlib = load_string_stdlib(); - let str_reverse_func = string_stdlib.get("str_reverse").expect("Function 'str_reverse' not found in string stdlib"); + let str_reverse_func = string_stdlib + .get("str_reverse") + .expect("Function 'str_reverse' not found in string stdlib"); assert_eq!(str_reverse_func.kind, Some(Type::TString)); - let params = str_reverse_func.params.as_ref().expect("Expected parameters for str_reverse"); + let params = str_reverse_func + .params + .as_ref() + .expect("Expected parameters for str_reverse"); assert_eq!(params.len(), 1); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); - match str_reverse_func.body.as_ref().expect("Expected body for str_reverse").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 1); - assert_eq!(*ret_type, Type::TString); - }, - _ => panic!("Expected MetaExp inside Return for str_reverse"), + match str_reverse_func + .body + .as_ref() + .expect("Expected body for str_reverse") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 1); + assert_eq!(*ret_type, Type::TString); } + _ => panic!("Expected MetaExp inside Return for str_reverse"), }, _ => panic!("Expected Return statement for str_reverse body"), } - } + } #[test] - fn test_load_string_stdlib_contains_cont_chars(){ + fn test_load_string_stdlib_contains_cont_chars() { let string_stdlib = load_string_stdlib(); - let cont_chars_func = string_stdlib.get("cont_chars").expect("Function 'cont_chars' not found in string stdlib"); + let cont_chars_func = string_stdlib + .get("cont_chars") + .expect("Function 'cont_chars' not found in string stdlib"); assert_eq!(cont_chars_func.kind, Some(Type::TInteger)); - let params = cont_chars_func.params.as_ref().expect("Expected parameters for cont_chars"); + let params = cont_chars_func + .params + .as_ref() + .expect("Expected parameters for cont_chars"); assert_eq!(params.len(), 2); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); assert_eq!(params[1].0, "c"); assert_eq!(params[1].1, Type::TString); - match cont_chars_func.body.as_ref().expect("Expected body for cont_chars").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 2); - assert_eq!(*ret_type, Type::TInteger); - }, - _ => panic!("Expected MetaExp inside Return for cont_chars"), + match cont_chars_func + .body + .as_ref() + .expect("Expected body for cont_chars") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TInteger); } + _ => panic!("Expected MetaExp inside Return for cont_chars"), }, _ => panic!("Expected Return statement for cont_chars body"), } } #[test] - fn test_load_string_stdlib_contains_filter_out_char(){ + fn test_load_string_stdlib_contains_filter_out_char() { let string_stdlib = load_string_stdlib(); - let filter_out_char_func = string_stdlib.get("filter_out_char").expect("Function 'filter_out_char' not found in string stdlib"); + let filter_out_char_func = string_stdlib + .get("filter_out_char") + .expect("Function 'filter_out_char' not found in string stdlib"); assert_eq!(filter_out_char_func.kind, Some(Type::TString)); - let params = filter_out_char_func.params.as_ref().expect("Expected parameters for filter_out_char"); + let params = filter_out_char_func + .params + .as_ref() + .expect("Expected parameters for filter_out_char"); assert_eq!(params.len(), 2); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); assert_eq!(params[1].0, "c"); assert_eq!(params[1].1, Type::TString); - match filter_out_char_func.body.as_ref().expect("Expected body for filter_out_char").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 2); - assert_eq!(*ret_type, Type::TString); - }, - _ => panic!("Expected MetaExp inside Return for filter_out_char"), + match filter_out_char_func + .body + .as_ref() + .expect("Expected body for filter_out_char") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 2); + assert_eq!(*ret_type, Type::TString); } + _ => panic!("Expected MetaExp inside Return for filter_out_char"), }, _ => panic!("Expected Return statement for filter_out_char body"), } } #[test] - fn test_load_string_stdlib_contains_replace(){ + fn test_load_string_stdlib_contains_replace() { let string_stdlib = load_string_stdlib(); - let replace_func = string_stdlib.get("replace").expect("Function 'replace' not found in string stdlib"); + let replace_func = string_stdlib + .get("replace") + .expect("Function 'replace' not found in string stdlib"); assert_eq!(replace_func.kind, Some(Type::TString)); - let params = replace_func.params.as_ref().expect("Expected parameters for replace"); + let params = replace_func + .params + .as_ref() + .expect("Expected parameters for replace"); assert_eq!(params.len(), 4); assert_eq!(params[0].0, "s"); assert_eq!(params[0].1, Type::TString); @@ -551,17 +708,20 @@ mod tests { assert_eq!(params[3].0, "count"); assert_eq!(params[3].1, Type::TInteger); - match replace_func.body.as_ref().expect("Expected body for replace").as_ref() { - Statement::Return(ref inner) => { - match **inner { - Expression::MetaExp(_, ref args, ref ret_type) => { - assert_eq!(args.len(), 4); - assert_eq!(*ret_type, Type::TString); - }, - _ => panic!("Expected MetaExp inside Return for replace"), + match replace_func + .body + .as_ref() + .expect("Expected body for replace") + .as_ref() + { + Statement::Return(ref inner) => match **inner { + Expression::MetaExp(_, ref args, ref ret_type) => { + assert_eq!(args.len(), 4); + assert_eq!(*ret_type, Type::TString); } + _ => panic!("Expected MetaExp inside Return for replace"), }, _ => panic!("Expected Return statement for replace body"), } } -} \ No newline at end of file +} diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index c8f78d0..248143f 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -1,6 +1,6 @@ -use std::collections::HashMap; -use crate::ir::ast::{Function, Type, Statement, Expression}; use crate::interpreter::interpreter::EnvValue; +use crate::ir::ast::{Expression, Function, Statement, Type}; +use std::collections::HashMap; pub fn load_string_stdlib() -> HashMap { let mut string_stdlib = HashMap::new(); @@ -110,7 +110,7 @@ pub fn load_string_stdlib() -> HashMap { ("s".to_string(), Type::TString), ("old".to_string(), Type::TString), ("new".to_string(), Type::TString), - ("count".to_string(), Type::TInteger), + ("count".to_string(), Type::TInteger), ]), body: Some(Box::new(Statement::Return(Box::new(Expression::MetaExp( replace_impl, @@ -167,7 +167,9 @@ pub fn str_reverse_impl(args: Vec) -> Result { return Err("str_reverse expects exactly one argument".to_string()); } if let EnvValue::Exp(Expression::CString(s)) = &args[0] { - Ok(EnvValue::Exp(Expression::CString(s.chars().rev().collect()))) + Ok(EnvValue::Exp(Expression::CString( + s.chars().rev().collect(), + ))) } else { Err("str_reverse expects a string argument".to_string()) } @@ -177,12 +179,16 @@ pub fn cont_chars_impl(args: Vec) -> Result { if args.len() != 2 { return Err("cont_chars expects exactly two arguments".to_string()); } - if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = (&args[0], &args[1]) { + if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = + (&args[0], &args[1]) + { if c.len() != 1 { return Err("cont_chars expects a single character as the second argument".to_string()); } let target = c.chars().next().unwrap(); - Ok(EnvValue::Exp(Expression::CInt(s.chars().filter(|&ch| ch == target).count() as i32))) + Ok(EnvValue::Exp(Expression::CInt( + s.chars().filter(|&ch| ch == target).count() as i32, + ))) } else { Err("cont_chars expects a string and a character as arguments".to_string()) } @@ -192,12 +198,18 @@ pub fn filter_out_char_impl(args: Vec) -> Result { if args.len() != 2 { return Err("filter_out_char expects exactly two arguments".to_string()); } - if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = (&args[0], &args[1]) { + if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(c))) = + (&args[0], &args[1]) + { if c.len() != 1 { - return Err("filter_out_char expects a single character as the second argument".to_string()); + return Err( + "filter_out_char expects a single character as the second argument".to_string(), + ); } let target = c.chars().next().unwrap(); - Ok(EnvValue::Exp(Expression::CString(s.chars().filter(|&ch| ch != target).collect()))) + Ok(EnvValue::Exp(Expression::CString( + s.chars().filter(|&ch| ch != target).collect(), + ))) } else { Err("filter_out_char expects a string and a character as arguments".to_string()) } @@ -207,7 +219,12 @@ pub fn replace_impl(args: Vec) -> Result { if args.len() < 3 || args.len() > 4 { return Err("replace expects between 3 and 4 arguments".to_string()); } - if let (EnvValue::Exp(Expression::CString(s)), EnvValue::Exp(Expression::CString(old)), EnvValue::Exp(Expression::CString(new))) = (&args[0], &args[1], &args[2]) { + if let ( + EnvValue::Exp(Expression::CString(s)), + EnvValue::Exp(Expression::CString(old)), + EnvValue::Exp(Expression::CString(new)), + ) = (&args[0], &args[1], &args[2]) + { let count = if args.len() == 4 { if let EnvValue::Exp(Expression::CInt(n)) = &args[3] { *n @@ -240,15 +257,15 @@ pub fn replace_impl(args: Vec) -> Result { } } - - #[cfg(test)] mod tests { use super::*; #[test] fn test_str_lower_valid_strings() { - let result = str_lower_impl(vec![EnvValue::Exp(Expression::CString(String::from("HELLO")))]); + let result = str_lower_impl(vec![EnvValue::Exp(Expression::CString(String::from( + "HELLO", + )))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CString(res_value))) = result { assert_eq!(res_value, "hello"); @@ -257,7 +274,9 @@ mod tests { #[test] fn test_str_length_valid_string() { - let result = str_length_impl(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); + let result = str_length_impl(vec![EnvValue::Exp(Expression::CString(String::from( + "hello", + )))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CInt(len))) = result { assert_eq!(len, 5); @@ -266,7 +285,9 @@ mod tests { #[test] fn test_str_reverse_valid_string() { - let result = str_reverse_impl(vec![EnvValue::Exp(Expression::CString(String::from("hello")))]); + let result = str_reverse_impl(vec![EnvValue::Exp(Expression::CString(String::from( + "hello", + )))]); assert!(result.is_ok()); if let Ok(EnvValue::Exp(Expression::CString(res_value))) = result { assert_eq!(res_value, "olleh"); @@ -309,5 +330,4 @@ mod tests { assert_eq!(res_value, "bonono"); } } - -} \ No newline at end of file +} diff --git a/src/tc/type_checker.rs b/src/tc/type_checker.rs index ee740d5..3d606dc 100644 --- a/src/tc/type_checker.rs +++ b/src/tc/type_checker.rs @@ -1081,19 +1081,19 @@ mod tests { Err(msg) => assert_eq!(msg, "[Parameter Error] Duplicate parameter name 'x'"), } } - + #[test] fn check_metaexp_sqrt() { let mut env = Environment::::new(); env.insert_variable("x".to_string(), Type::TReal); - + let meta_expr = Expression::MetaExp( sqrt_impl, vec![Expression::Var("x".to_string())], Type::TReal, ); - + let result_type = check_exp(meta_expr, &env).expect("Type checking failed"); assert_eq!(result_type, Type::TReal); } -} \ No newline at end of file +}