structure

This commit is contained in:
WanderingPenwing 2024-12-09 12:05:18 +01:00
parent b401736bb4
commit a8b1110f97
6 changed files with 146 additions and 91 deletions

View file

@ -1,6 +1,6 @@
use super::Sophie; use super::Sophie;
use super::ErreurSophie; use super::ErreurSophie;
use super::Variable; use super::Element;
impl Sophie { impl Sophie {
pub fn condition(&self, arguments: &str) -> Result<bool, ErreurSophie> { pub fn condition(&self, arguments: &str) -> Result<bool, ErreurSophie> {
@ -64,8 +64,8 @@ impl Sophie {
pub fn texte_comme_booleen(&self, texte: &str) -> Result<bool, ErreurSophie> { pub fn texte_comme_booleen(&self, texte: &str) -> Result<bool, ErreurSophie> {
if texte.chars().next().map_or(false, |c| c.is_uppercase()) { if texte.chars().next().map_or(false, |c| c.is_uppercase()) {
if self.variables.contains_key(texte) { if self.variables.contains_key(texte) {
let Variable::Booleen(booleen) = self.variables[texte] else { let Element::Booleen(booleen) = self.variables[texte] else {
return Err(ErreurSophie::MauvaisType(texte.into(), self.variables[texte].nom_type(), "booleen".into())) return Err(ErreurSophie::MauvaisType(texte.into(), self.variables[texte].type_element().nom(), "booleen".into()))
}; };
return Ok(booleen); return Ok(booleen);
} else { } else {

View file

@ -1,67 +1,17 @@
use std::fmt;
use std::io; use std::io;
use std::collections::HashMap; use std::collections::HashMap;
pub mod nombre; pub mod nombre;
pub mod texte; pub mod texte;
pub mod booleen; pub mod booleen;
pub mod structure;
use structure::*;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
#[derive(PartialEq, Debug, Clone)]
pub enum Variable {
Entier(usize),
Texte(String),
Booleen(bool),
}
impl Variable {
pub fn nom_type(&self) -> String {
match self {
Self::Entier(_) => "entier".into(),
Self::Texte(_) => "texte".into(),
Self::Booleen(_) => "booléen".into(),
}
}
}
pub enum ErreurSophie {
CommandeInconnue(String),
PhraseVide,
ManqueArgument,
NombreInvalide(String),
BooleenInvalide(String),
TexteInvalide(String),
MauvaisArgument(String),
DesequilibreParenthese,
VariableInconnue(String),
MauvaisType(String, String, String),
ProblemeTerminal(String),
ManquePoint,
}
impl fmt::Display for ErreurSophie {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
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::NombreInvalide(nombre) => write!(f, "Le nombre \"{}\" est mal orthographié.", nombre),
Self::TexteInvalide(raison) => write!(f, "Le texte est invalide, {}.", raison),
Self::BooleenInvalide(booleen) => write!(f, "Le booleen \"{}\" est mal orthographié.", booleen),
Self::MauvaisArgument(message) => write!(f, "La commande a reçu un mauvais argument, {}.", message),
Self::DesequilibreParenthese => write!(f, "Les parenthèses sont déséquilibrés."),
Self::VariableInconnue(nom) => write!(f, "La variable \"{}\" est inconnue.", nom),
Self::MauvaisType(nom, type_variable, type_attendu) => write!(f, "La variable {} est du mauvais type ({}), attendais {}.", nom, type_variable, type_attendu),
Self::ProblemeTerminal(probleme) => write!(f, "Problème d'accès terminal : {}.", probleme),
Self::ManquePoint => write!(f, "Il manque un point."),
}
}
}
pub struct Sophie { pub struct Sophie {
variables: HashMap<String, Variable>, variables: HashMap<String, Element>,
} }
impl Sophie { impl Sophie {
@ -140,9 +90,9 @@ impl Sophie {
}; };
let contenu = match variable_type.as_str() { let contenu = match variable_type.as_str() {
"entier" => Variable::Entier(0), "entier" => Element::Entier(0),
"texte" => Variable::Texte("".to_string()), "texte" => Element::Texte("".to_string()),
"booléen" => Variable::Booleen(false), "booléen" => Element::Booleen(false),
_ => return Err(ErreurSophie::MauvaisArgument(format!("type de variable \"{}\" inconnu", variable_type))), _ => return Err(ErreurSophie::MauvaisArgument(format!("type de variable \"{}\" inconnu", variable_type))),
}; };
@ -154,10 +104,10 @@ impl Sophie {
let (variable_nom, contenu) = self.nom_de_variable(arguments, "avec")?; let (variable_nom, contenu) = self.nom_de_variable(arguments, "avec")?;
let variable = self.recupere_variable(&variable_nom)?; let variable = self.recupere_variable(&variable_nom)?;
let valeur = match variable { let valeur = match variable.type_element() {
Variable::Entier(_) => Variable::Entier(self.operation(&contenu)?), TypeElement::Entier => Element::Entier(self.operation(&contenu)?),
Variable::Texte(_) => Variable::Texte(self.texte(&contenu)?), TypeElement::Texte => Element::Texte(self.texte(&contenu)?),
Variable::Booleen(_) => Variable::Booleen(self.condition(&contenu)?), TypeElement::Booleen => Element::Booleen(self.condition(&contenu)?),
}; };
self.variables.insert(variable_nom, valeur); self.variables.insert(variable_nom, valeur);
@ -177,17 +127,17 @@ impl Sophie {
let contenu = reponse.trim(); let contenu = reponse.trim();
let valeur = match self.variables[&variable_nom] { let valeur = match self.variables[&variable_nom].type_element() {
Variable::Entier(_) => Variable::Entier(nombre::texte_comme_nombre(contenu)?), TypeElement::Entier => Element::Entier(nombre::texte_comme_nombre(contenu)?),
Variable::Texte(_) => Variable::Texte(contenu.into()), TypeElement::Texte => Element::Texte(contenu.into()),
Variable::Booleen(_) => Variable::Booleen(booleen::texte_comme_booleen(contenu)?), TypeElement::Booleen => Element::Booleen(booleen::texte_comme_booleen(contenu)?)
}; };
self.variables.insert(variable_nom, valeur); self.variables.insert(variable_nom, valeur);
Ok(()) Ok(())
} }
fn recupere_variable(&self, nom: &str) -> Result<Variable, ErreurSophie> { fn recupere_variable(&self, nom: &str) -> Result<Element, ErreurSophie> {
let Some(first_char) = nom.chars().next() else { let Some(first_char) = nom.chars().next() else {
return Err(ErreurSophie::MauvaisArgument("il n'y a pas de variable".to_string())) return Err(ErreurSophie::MauvaisArgument("il n'y a pas de variable".to_string()))
}; };

View file

@ -1,6 +1,6 @@
use super::ErreurSophie; use super::ErreurSophie;
use super::Sophie; use super::Sophie;
use super::Variable; use super::Element;
const NOMS_UNITES: [&str; 10] = ["", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf"]; const NOMS_UNITES: [&str; 10] = ["", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf"];
const NOMS_UNITES_DIX: [&str; 10] = ["dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf"]; const NOMS_UNITES_DIX: [&str; 10] = ["dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf"];
@ -100,8 +100,8 @@ impl Sophie {
pub fn texte_comme_nombre(&self, texte: &str) -> Result<usize, ErreurSophie> { pub fn texte_comme_nombre(&self, texte: &str) -> Result<usize, ErreurSophie> {
if texte.chars().next().map_or(false, |c| c.is_uppercase()) { if texte.chars().next().map_or(false, |c| c.is_uppercase()) {
if self.variables.contains_key(texte) { if self.variables.contains_key(texte) {
let Variable::Entier(nombre) = self.variables[texte] else { let Element::Entier(nombre) = self.variables[texte] else {
return Err(ErreurSophie::MauvaisType(texte.into(), self.variables[texte].nom_type(), "entier".into())) return Err(ErreurSophie::MauvaisType(texte.into(), self.variables[texte].type_element().nom(), "entier".into()))
}; };
return Ok(nombre); return Ok(nombre);
} else { } else {

105
src/sophie/structure.rs Normal file
View file

@ -0,0 +1,105 @@
use std::fmt;
pub enum Commande {
Definis(String, TypeElement),
Demande(String),
Modifie(String, Expression),
Affiche(Expression),
}
#[derive(PartialEq, Debug, Clone)]
pub struct Expression {
type_expression: TypeElement,
contenu: Vec<Element>
}
impl Expression {
fn nouvelle(type_expression: TypeElement) -> Self {
Self {
type_expression,
contenu: vec![]
}
}
fn ajoute(&mut self, element: Element) -> Result<(), ErreurSophie> {
let type_element = element.type_element();
if self.type_expression != type_element {
return Err(ErreurSophie::MauvaisType("inconnue".into(), type_element.nom(), self.type_expression.nom()))
}
self.contenu.push(element);
Ok(())
}
}
#[derive(PartialEq, Debug, Clone)]
pub enum TypeElement {
Entier,
Texte,
Booleen,
}
impl TypeElement {
pub fn nom(&self) -> String {
match self {
Self::Entier => "entier".into(),
Self::Texte => "texte".into(),
Self::Booleen => "booléen".into(),
}
}
}
#[derive(PartialEq, Debug, Clone)]
pub enum Element {
Entier(usize),
Texte(String),
Booleen(bool),
Variable(String, TypeElement),
Operateur(String, TypeElement),
Expression(Expression, TypeElement),
}
impl Element {
pub fn type_element(&self) -> TypeElement {
match self {
Self::Entier(_) => TypeElement::Entier,
Self::Texte(_) => TypeElement::Texte,
Self::Booleen(_) => TypeElement::Booleen,
Self::Variable(_, type_element) => type_element.clone(),
Self::Operateur(_, type_element) => type_element.clone(),
Self::Expression(_, type_element) => type_element.clone(),
}
}
}
pub enum ErreurSophie {
CommandeInconnue(String),
PhraseVide,
ManqueArgument,
NombreInvalide(String),
BooleenInvalide(String),
TexteInvalide(String),
MauvaisArgument(String),
DesequilibreParenthese,
VariableInconnue(String),
MauvaisType(String, String, String),
ProblemeTerminal(String),
ManquePoint,
}
impl fmt::Display for ErreurSophie {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
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::NombreInvalide(nombre) => write!(f, "Le nombre \"{}\" est mal orthographié.", nombre),
Self::TexteInvalide(raison) => write!(f, "Le texte est invalide, {}.", raison),
Self::BooleenInvalide(booleen) => write!(f, "Le booleen \"{}\" est mal orthographié.", booleen),
Self::MauvaisArgument(message) => write!(f, "La commande a reçu un mauvais argument, {}.", message),
Self::DesequilibreParenthese => write!(f, "Les parenthèses sont déséquilibrés."),
Self::VariableInconnue(nom) => write!(f, "La variable \"{}\" est inconnue.", nom),
Self::MauvaisType(nom, type_variable, type_attendu) => write!(f, "La variable {} est du mauvais type ({}), attendais {}.", nom, type_variable, type_attendu),
Self::ProblemeTerminal(probleme) => write!(f, "Problème d'accès terminal : {}.", probleme),
Self::ManquePoint => write!(f, "Il manque un point."),
}
}
}

View file

@ -36,10 +36,10 @@ fn teste_somme() {
#[test] #[test]
fn teste_definition_variable() { fn teste_definition_variable() {
let mut sophie = Sophie::new(); let mut sophie = Sophie::new();
let resultat = sophie.execute_phrase("Définie Variable comme entier"); let resultat = sophie.execute_phrase("Définis Element comme entier");
match resultat { match resultat {
Ok(_) => { Ok(_) => {
assert_eq!(sophie.variables["Variable"], Variable::Entier(0), "Variable mal définie"); assert_eq!(sophie.variables["Element"], Element::Entier(0), "Element mal définie");
} }
Err(raison) => { Err(raison) => {
panic!("Définition de variable échouée : {}", raison); panic!("Définition de variable échouée : {}", raison);
@ -50,14 +50,14 @@ fn teste_definition_variable() {
#[test] #[test]
fn teste_modification_variable() { fn teste_modification_variable() {
let mut sophie = Sophie::new(); let mut sophie = Sophie::new();
if let Err(raison) = sophie.execute_phrase("Définie Variable comme entier") { if let Err(raison) = sophie.execute_phrase("Définis Element comme entier") {
panic!("Définition de variable échouée : {}", raison); panic!("Définition de variable échouée : {}", raison);
} }
let a = 2345678; let a = 2345678;
let resultat = sophie.execute_phrase(&format!("Modifie Variable avec {} ", nombre::nombre_comme_texte(a))); let resultat = sophie.execute_phrase(&format!("Modifie Element avec {} ", nombre::nombre_comme_texte(a)));
match resultat { match resultat {
Ok(_) => { Ok(_) => {
assert_eq!(sophie.variables["Variable"], Variable::Entier(a), "Variable mal modifiée"); assert_eq!(sophie.variables["Element"], Element::Entier(a), "Element mal modifiée");
} }
Err(raison) => { Err(raison) => {
panic!("Modification de variable échouée : {}", raison); panic!("Modification de variable échouée : {}", raison);
@ -68,15 +68,15 @@ fn teste_modification_variable() {
#[test] #[test]
fn teste_operation_variable() { fn teste_operation_variable() {
let mut sophie = Sophie::new(); let mut sophie = Sophie::new();
if let Err(raison) = sophie.execute_phrase("Définie Variable comme entier") { if let Err(raison) = sophie.execute_phrase("Définis Element comme entier") {
panic!("Définition de variable échouée : {}", raison); panic!("Définition de variable échouée : {}", raison);
} }
let a = 2345678; let a = 2345678;
if let Err(raison) = sophie.execute_phrase(&format!("Modifie Variable avec {} ", nombre::nombre_comme_texte(a))) { if let Err(raison) = sophie.execute_phrase(&format!("Modifie Element avec {} ", nombre::nombre_comme_texte(a))) {
panic!("Modification de variable échouée : {}", raison); panic!("Modification de variable échouée : {}", raison);
} }
let b = 987654; let b = 987654;
let resultat = sophie.operation(&format!("Variable plus {}", nombre::nombre_comme_texte(b))); let resultat = sophie.operation(&format!("Element plus {}", nombre::nombre_comme_texte(b)));
match resultat { match resultat {
Ok(nombre) => { 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); assert_eq!(nombre, a+b, "Echec de la somme d'un entier et d'une variable, attendais {}, a reçu {}", a+b, nombre);
@ -114,14 +114,14 @@ fn teste_maths() {
#[test] #[test]
fn teste_texte() { fn teste_texte() {
let mut sophie = Sophie::new(); let mut sophie = Sophie::new();
if let Err(raison) = sophie.execute_phrase("Définie A comme entier") { if let Err(raison) = sophie.execute_phrase("Définis A comme entier") {
panic!("Définition de variable échouée : {}", raison); panic!("Définition de variable échouée : {}", raison);
} }
let a = 2345678; let a = 2345678;
if let Err(raison) = sophie.execute_phrase(&format!("Modifie A avec {} ", nombre::nombre_comme_texte(a))) { if let Err(raison) = sophie.execute_phrase(&format!("Modifie A avec {} ", nombre::nombre_comme_texte(a))) {
panic!("Modification de variable échouée : {}", raison); panic!("Modification de variable échouée : {}", raison);
} }
if let Err(raison) = sophie.execute_phrase("Définie B comme texte") { if let Err(raison) = sophie.execute_phrase("Définis B comme texte") {
panic!("Définition de variable échouée : {}", raison); panic!("Définition de variable échouée : {}", raison);
} }
if let Err(raison) = sophie.execute_phrase("Modifie B avec \"hello there\", \" general\", \" Kenobi\"") { if let Err(raison) = sophie.execute_phrase("Modifie B avec \"hello there\", \" general\", \" Kenobi\"") {
@ -140,14 +140,14 @@ fn teste_texte() {
#[test] #[test]
fn teste_redefinition_variable() { fn teste_redefinition_variable() {
let mut sophie = Sophie::new(); let mut sophie = Sophie::new();
if let Err(raison) = sophie.execute_phrase("Définie Variable comme entier") { if let Err(raison) = sophie.execute_phrase("Définis Element comme entier") {
panic!("Définition de variable échouée : {}", raison); panic!("Définition de variable échouée : {}", raison);
}; };
let Err(raison) = sophie.execute_phrase("Définie Variable comme texte") else { let Err(raison) = sophie.execute_phrase("Définis Element comme texte") else {
panic!("Ne devrais pas pouvoir redéfinir une variable"); panic!("Ne devrais pas pouvoir redéfinir une variable");
}; };
if let ErreurSophie::MauvaisArgument(ref texte) = raison { if let ErreurSophie::MauvaisArgument(ref texte) = raison {
assert_eq!(texte, "la variable \"Variable\" existe déjà", "Définition échouée avec erreur imprévue : {}", raison); assert_eq!(texte, "la variable \"Element\" existe déjà", "Définition échouée avec erreur imprévue : {}", raison);
} else { } else {
panic!("Définition échouée avec erreur imprévue : {}", raison); panic!("Définition échouée avec erreur imprévue : {}", raison);
} }
@ -156,12 +156,12 @@ fn teste_redefinition_variable() {
#[test] #[test]
fn teste_echec_modification() { fn teste_echec_modification() {
let mut sophie = Sophie::new(); let mut sophie = Sophie::new();
let resultat = sophie.execute_phrase("Modifie Variable avec deux"); let resultat = sophie.execute_phrase("Modifie Element avec deux");
let Err(raison) = resultat else { let Err(raison) = resultat else {
panic!("Ne devrais pas pouvoir modifier une variable non définie"); panic!("Ne devrais pas pouvoir modifier une variable non définie");
}; };
if let ErreurSophie::VariableInconnue(nom) = raison { if let ErreurSophie::VariableInconnue(nom) = raison {
assert_eq!(nom, "Variable", "Mauvais nom de variable reconnu : {}", nom); assert_eq!(nom, "Element", "Mauvais nom de variable reconnu : {}", nom);
} else { } else {
panic!("Modification échouée avec erreur imprévue : {}", raison); panic!("Modification échouée avec erreur imprévue : {}", raison);
} }
@ -170,7 +170,7 @@ fn teste_echec_modification() {
#[test] #[test]
fn teste_majuscule_variable() { fn teste_majuscule_variable() {
let mut sophie = Sophie::new(); let mut sophie = Sophie::new();
let resultat = sophie.execute_phrase("Définie variable comme entier"); let resultat = sophie.execute_phrase("Définis variable comme entier");
let Err(raison) = resultat else { let Err(raison) = resultat else {
panic!("Ne devrais pas pouvoir definir une variable sans majuscule"); panic!("Ne devrais pas pouvoir definir une variable sans majuscule");
}; };
@ -184,7 +184,7 @@ fn teste_majuscule_variable() {
#[test] #[test]
fn teste_point_phrase() { fn teste_point_phrase() {
let mut sophie = Sophie::new(); let mut sophie = Sophie::new();
let resultat = sophie.execute("Définie Variable comme entier".into()); let resultat = sophie.execute("Définis Element comme entier".into());
let Err(raison) = resultat else { let Err(raison) = resultat else {
panic!("Ne devrais pas pouvoir faire de commande sans point à la fin"); panic!("Ne devrais pas pouvoir faire de commande sans point à la fin");
}; };

View file

@ -1,6 +1,6 @@
use super::Sophie; use super::Sophie;
use super::ErreurSophie; use super::ErreurSophie;
use super::Variable; use super::Element;
use super::nombre; use super::nombre;
use super::booleen; use super::booleen;
@ -33,8 +33,8 @@ impl Sophie {
let variable = self.recupere_variable(argument)?; let variable = self.recupere_variable(argument)?;
let Variable::Texte(contenu) = variable else { let Element::Texte(contenu) = variable else {
return Err(ErreurSophie::MauvaisType(argument.into(), variable.nom_type(), "texte".into())) return Err(ErreurSophie::MauvaisType(argument.into(), variable.type_element().nom(), "texte".into()))
}; };
texte += &contenu; texte += &contenu;