From 5d100ec8f7d505faa25fc0c435a4ec9120bab27e Mon Sep 17 00:00:00 2001 From: WanderingPenwing Date: Sat, 7 Dec 2024 10:43:48 +0100 Subject: [PATCH] variables --- src/main.rs | 251 +++++++++++++++++++++++++++++++++---------------- src/nombres.rs | 16 +--- test.sp | 5 +- 3 files changed, 172 insertions(+), 100 deletions(-) diff --git a/src/main.rs b/src/main.rs index 50565f8..bad57ab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,16 @@ use std::env; use std::fs; use std::fmt; +use std::collections::HashMap; mod nombres; enum ErreurSophie { CommandeInconnue(String), PhraseVide, - ManqueArgument, + ManqueArgument(String), OrthographeNombre(String), + MauvaisArgument(String), } impl fmt::Display for ErreurSophie { @@ -16,12 +18,131 @@ impl fmt::Display for ErreurSophie { match self { Self::CommandeInconnue(commande) => write!(f, "La commande \"{}\" est inconnue.", commande), Self::PhraseVide => write!(f, "La phrase est vide."), - Self::ManqueArgument => write!(f, "Il manque un argument."), + Self::ManqueArgument(commande) => write!(f, "Il manque un argument pour \"{}\".", commande), Self::OrthographeNombre(nombre) => write!(f, "Le nombre \"{}\" est mal orthographié.", nombre), + Self::MauvaisArgument(message) => write!(f, "La commande a reçu un mauvais argument, {}.", message) } } } +struct Sophie { + variables: HashMap, +} + +impl Sophie { + fn new() -> Self { + Self { + variables: HashMap::new(), + } + } + fn execute(&mut self, contenu: String) { + let contenu_propre = contenu.replace("\n", ""); + let mut texte: Vec<&str> = contenu_propre.split('.').collect(); + texte.pop(); // remove empty phrase after last dot + for (index_phrase, phrase) in texte.iter().enumerate() { + match self.execute_phrase(phrase) { + Ok(_) => {}, + Err(raison) => { + eprintln!("Erreur phrase {} : {}", index_phrase + 1, raison); + return + } + } + } + } + + fn execute_phrase(&mut self, phrase: &str) -> Result<(), ErreurSophie> { + let phrase = phrase.trim(); + let parties: Vec<&str> = phrase.splitn(2, ' ').collect(); + + if parties.is_empty() { + return Err(ErreurSophie::PhraseVide) + } + + if parties.len() == 1 { + return Err(ErreurSophie::ManqueArgument(parties[0].to_string())) + } + + match parties[0] { + "Modifie" => { + self.modifie(parties[1])?; + }, + "Affiche" => { + self.affiche(parties[1])?; + }, + "Demande" => { + self.demande(parties[1])?; + } + autre_commande => { + return Err(ErreurSophie::CommandeInconnue(autre_commande.to_string())) + } + }; + Ok(()) + } + + fn modifie(&mut self, arguments: &str) -> Result<(), ErreurSophie> { + let parties: Vec<&str> = arguments.splitn(2, "avec").collect(); + if parties.len() == 1 { + return Err(ErreurSophie::ManqueArgument(format!("Modifie {}", parties[0]))) + } + let variable: String = parties[0].trim().to_string(); + + let Some(first_char) = variable.chars().next() else { + return Err(ErreurSophie::MauvaisArgument("il n'y a pas de variable pour la commande Modifie".to_string())) + }; + if !first_char.is_uppercase() { + return Err(ErreurSophie::MauvaisArgument("il manque une majuscule à la variable pour la commande Modifie".to_string())) + } + + let valeur = self.operation(parties[1].trim())?; + self.variables.insert(variable, valeur); + + Ok(()) + } + + fn affiche(&self, arguments: &str) -> Result<(), ErreurSophie> { + let liste_arguments: Vec<&str> = arguments.split(',').collect(); + + let mut texte = "".to_string(); + + for argument in liste_arguments { + let argument: &str = argument.trim(); + if argument.starts_with('"') { + if argument.ends_with('"') { + texte += &argument[1..argument.len()-1]; + } + } else { + let resultat = self.operation(argument)?; + texte += &nombres::nombre_comme_texte(resultat); + } + } + println!("{}", texte); + Ok(()) + } + + fn demande(&self, arguments: &str) -> Result<(), ErreurSophie> { + println!("- demande : {}", arguments); + Ok(()) + } + + pub fn operation(&self, arguments: &str) -> Result { + let somme_texte: Vec<&str> = arguments.split("plus").collect(); + let mut somme : usize = 0; + for element in somme_texte { + let element_propre: &str = element.trim(); + let Some(first_char) = element_propre.chars().next() else { + return Err(ErreurSophie::MauvaisArgument("il y a un argument vide pour l'operation".to_string())) + }; + let nombre = if first_char.is_uppercase() { + self.variables[element_propre] + } else { + nombres::texte_comme_nombre(element_propre)? + }; + somme += nombre; + } + Ok(somme) + } +} + fn main() { let arguments: Vec = env::args().collect(); @@ -31,10 +152,11 @@ fn main() { } let chemin_de_fichier = &arguments[1]; + let mut sophie = Sophie::new(); match fs::read_to_string(chemin_de_fichier) { Ok(contenu) => { - execute(contenu); + sophie.execute(contenu); } Err(raison) => { eprintln!("Fichier illisible : {}", raison); @@ -42,80 +164,6 @@ fn main() { } } -fn execute(contenu: String) { - let contenu_propre = contenu.replace("\n", ""); - let mut texte: Vec<&str> = contenu_propre.split('.').collect(); - texte.pop(); // remove empty phrase after last dot - for (index_phrase, phrase) in texte.iter().enumerate() { - match execute_phrase(phrase) { - Ok(_) => {}, - Err(raison) => { - eprintln!("Erreur phrase {} : {}", index_phrase + 1, raison); - return - } - } - } -} - -fn execute_phrase(phrase: &str) -> Result<(), ErreurSophie> { - let phrase = phrase.trim(); - let parties: Vec<&str> = phrase.splitn(2, ' ').collect(); - - if parties.is_empty() { - return Err(ErreurSophie::PhraseVide) - } - - if parties.len() == 1 { - return Err(ErreurSophie::ManqueArgument) - } - - match parties[0] { - "Modifie" => { - modifie(parties[1])?; - }, - "Affiche" => { - affiche(parties[1])?; - }, - "Demande" => { - demande(parties[1])?; - } - autre_commande => { - return Err(ErreurSophie::CommandeInconnue(autre_commande.to_string())) - } - }; - Ok(()) -} - -fn modifie(arguments: &str) -> Result<(), ErreurSophie> { - println!("- modifie : {}", arguments); - Ok(()) -} - -fn affiche(arguments: &str) -> Result<(), ErreurSophie> { - let liste_arguments: Vec<&str> = arguments.split(',').collect(); - - let mut texte = "".to_string(); - - for argument in liste_arguments { - let argument: &str = argument.trim(); - if argument.starts_with('"') { - if argument.ends_with('"') { - texte += &argument[1..argument.len()-1]; - } - } else { - let resultat = nombres::operation(argument)?; - texte += &nombres::nombre_comme_texte(resultat); - } - } - println!("{}", texte); - Ok(()) -} - -fn demande(arguments: &str) -> Result<(), ErreurSophie> { - println!("- demande : {}", arguments); - Ok(()) -} - #[cfg(test)] // Compile and run only during testing @@ -129,10 +177,10 @@ mod tests { let texte = nombres::nombre_comme_texte(*i); // Convert number to text match nombres::texte_comme_nombre(&texte) { // Convert text back to number Ok(nombre) => { - assert_eq!(*i, nombre, "Mismatch for number: {}, text: {}", i, texte); + assert_eq!(*i, nombre, "Nombre inexact : {}, texte : {}", i, texte); } Err(raison) => { - panic!("Conversion failed for number: {} with error: {}", i, raison); + panic!("Conversion échouée pour : {}, avec l'erreur : {}", i, raison); } } } @@ -140,18 +188,55 @@ mod tests { #[test] fn teste_somme() { - for (a, b) in [(5, 7), (1467,45678), (1001, 0), (72_036_854_775_807usize, 14_036_567_775_807usize)] { + for (a, b) in [(0, 0), (5, 7), (1467,45678), (1001, 0), (72_036_854_775_807usize, 14_036_567_775_807usize)] { let texte_a = nombres::nombre_comme_texte(a); let texte_b = nombres::nombre_comme_texte(b); - let resultat = nombres::operation(&format!("{} plus {}", texte_a, texte_b)); + let sophie = Sophie::new(); + let resultat = sophie.operation(&format!("{} plus {}", texte_a, texte_b)); match resultat { // Convert text back to number Ok(nombre) => { - assert_eq!(a+b, nombre, "Mismatch for {}+{}, got: {}", a, b, nombre); + assert_eq!(a+b, nombre, "Résultat inexact pour {}+{} : {}", a, b, nombre); } Err(raison) => { - panic!("Conversion failed for number: ({},{}) with error: {}", a, b, raison); + panic!("Conversion échouée pour : ({},{}), avec l'erreur : {}", a, b, raison); } } } } + + #[test] + fn teste_initialisation_variable() { + let mut sophie = Sophie::new(); + let phrase = "Modifie Variable avec trois plus cent-deux"; + let resultat = sophie.execute_phrase(phrase); + match resultat { + Ok(_) => { + assert_eq!(sophie.variables["Variable"], 105, "Echec d'initialisation de variable"); + } + Err(raison) => { + panic!("Execution échouée pour \"{}\", avec l'erreur : {}", phrase, raison); + } + } + } + + #[test] + fn teste_operation_variable() { + let mut sophie = Sophie::new(); + let a = 2345678; + let b = 987654; + let phrase = format!("Modifie Variable avec {}", nombres::nombre_comme_texte(a)); + if let Err(raison) = sophie.execute_phrase(&phrase) { + panic!("Execution échouée pour \"{}\", avec l'erreur : {}", phrase, raison); + } + let resultat = sophie.operation(&format!("Variable plus {}", nombres::nombre_comme_texte(b))); + + match resultat { + Ok(nombre) => { + assert_eq!(nombre, a+b, "Echec de la somme d'un entier et d'une variable, attendais {}, a reçu {}", a+b, nombre); + } + Err(raison) => { + panic!("Execution échouée pour \"Variable plus {}\", avec l'erreur : {}", nombres::nombre_comme_texte(b), raison); + } + } + } } diff --git a/src/nombres.rs b/src/nombres.rs index b5de811..93a31ff 100644 --- a/src/nombres.rs +++ b/src/nombres.rs @@ -78,7 +78,7 @@ fn petit_nombre_comme_texte(nombre: usize) -> String { let séparation = if unité == 1 && ![0, 1, 8, 9].contains(&dizaine) {UNION.to_string() + "et"} else {"".to_string()}; - let unité_union = if nombre - unité > 0 && unité > 0 { + let unité_union = if nombre - unité > 0 && unité > 0 && nombre > 16 { UNION.to_string() } else { "".to_string() @@ -93,7 +93,6 @@ fn petit_nombre_comme_texte(nombre: usize) -> String { } pub fn texte_comme_nombre(texte: &str) -> Result { - println!("texte:{}", texte); if texte == "zéro" { return Ok(0) } @@ -124,7 +123,6 @@ pub fn texte_comme_nombre(texte: &str) -> Result { } texte_modifie = texte_separe[1].trim_start_matches(UNION); } - println!("{}/{:?}", &texte_modifie, petits_nombres_texte); } let petit_nombre_texte = texte_modifie .trim_start_matches(&pluriel) @@ -132,8 +130,6 @@ pub fn texte_comme_nombre(texte: &str) -> Result { .trim_end_matches(UNION); petits_nombres_texte.push(petit_nombre_texte); - println!("ptn:{:?}", petits_nombres_texte); - let mut nombre: usize = 0; for (index, petit_nombre_texte) in petits_nombres_texte.iter().enumerate() { @@ -203,13 +199,3 @@ fn texte_comme_petit_nombre(texte: &str) -> Result { Ok(nombre) } - -pub fn operation(arguments: &str) -> Result { - let somme_texte: Vec<&str> = arguments.split("plus").collect(); - let mut somme : usize = 0; - for element in somme_texte { - let element_propre: &str = element.trim(); - somme += texte_comme_nombre(element_propre)? - } - Ok(somme) -} diff --git a/test.sp b/test.sp index 6849387..7faf9d2 100644 --- a/test.sp +++ b/test.sp @@ -1,2 +1,3 @@ -Affiche "Nombre 1 : ", deux-million plus mille-sept-cent-trente-deux. -Affiche "Nombre 2 : ", sept-cent plus cinq-cent-quarante-quatre. +Modifie Variable avec trois plus douze. +Affiche "Resultat : ", Variable. +Affiche "Test : ", Variable plus soixante-dix.