better structuure
This commit is contained in:
parent
797b9991ea
commit
7ad8b8106b
17
src/main.rs
17
src/main.rs
|
@ -11,13 +11,26 @@ fn main() {
|
||||||
eprintln!("Utilisation : pendragon <FILE>");
|
eprintln!("Utilisation : pendragon <FILE>");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let debug_mode = arguments.contains(&"--debug".to_string());
|
||||||
|
|
||||||
let chemin_de_fichier = &arguments[1];
|
let chemin_de_fichier = &arguments[1];
|
||||||
let mut pendragon = Pendragon::new();
|
let mut pendragon = Pendragon::nouveau();
|
||||||
|
|
||||||
match fs::read_to_string(chemin_de_fichier) {
|
match fs::read_to_string(chemin_de_fichier) {
|
||||||
Ok(contenu) => {
|
Ok(contenu) => {
|
||||||
let _ = pendragon.compile(contenu);
|
let Ok(_) = pendragon.compile(contenu) else {
|
||||||
|
eprintln!("Compilation interrompue");
|
||||||
|
return
|
||||||
|
};
|
||||||
|
if debug_mode {
|
||||||
|
println!("{}\n-----------", pendragon.programme);
|
||||||
|
}
|
||||||
|
if let Err(raison) = pendragon.programme.execute() {
|
||||||
|
eprintln!("Erreur Execution : {}", raison);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
println!("\n# Success");
|
||||||
}
|
}
|
||||||
Err(raison) => {
|
Err(raison) => {
|
||||||
eprintln!("Fichier illisible : {}", raison);
|
eprintln!("Fichier illisible : {}", raison);
|
||||||
|
|
|
@ -1,79 +1,119 @@
|
||||||
use super::Pendragon;
|
use super::*;
|
||||||
use super::ErreurPendragon;
|
|
||||||
use super::Element;
|
|
||||||
|
|
||||||
impl Pendragon {
|
impl Pendragon {
|
||||||
pub fn condition(&self, arguments: &str) -> Result<bool, ErreurPendragon> {
|
pub fn elements_booleen(&self, arguments: &str) -> Result<Vec<Element>, ErreurPendragon> {
|
||||||
self.condition_elementaire(arguments)
|
let texte = arguments
|
||||||
}
|
.replace("ouvre la parenthèse", "ouvre-la-parenthese")
|
||||||
|
.replace("ferme la parenthèse", "ferme-la-parenthese");
|
||||||
|
let elements_texte: Vec<&str> = texte.split(" ").collect();
|
||||||
|
let mut expression: Vec<Element> = Vec::new();
|
||||||
|
let mut pile_operateurs: Vec<Operateur> = Vec::new();
|
||||||
|
|
||||||
pub fn condition_elementaire(&self, texte: &str) -> Result<bool, ErreurPendragon> {
|
for element in elements_texte {
|
||||||
let mut expression: Vec<String> = texte.split(" ").map(String::from).collect();
|
match element {
|
||||||
|
"vrai" => expression.push(Element::Booleen(true)),
|
||||||
|
"faux" => expression.push(Element::Booleen(false)),
|
||||||
|
"non" => pile_operateurs.push(Operateur::Non),
|
||||||
|
"et" => {
|
||||||
|
while let Some(operateur) = pile_operateurs.last() {
|
||||||
|
if *operateur == Operateur::Non || *operateur == Operateur::Et {
|
||||||
|
expression.push(Element::Operateur(pile_operateurs.pop().unwrap()));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pile_operateurs.push(Operateur::Et);
|
||||||
|
}
|
||||||
|
"ou" => {
|
||||||
|
while let Some(operateur) = pile_operateurs.last() {
|
||||||
|
if *operateur == Operateur::Non || *operateur == Operateur::Et || *operateur == Operateur::Ou {
|
||||||
|
expression.push(Element::Operateur(pile_operateurs.pop().unwrap()));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pile_operateurs.push(Operateur::Ou);
|
||||||
|
}
|
||||||
|
"ouvre-la-parenthese" => pile_operateurs.push(Operateur::ParentheseBooleen),
|
||||||
|
"ferme-la-parenthese" => {
|
||||||
|
while let Some(operateur) = pile_operateurs.pop() {
|
||||||
|
if operateur == Operateur::ParentheseBooleen {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
expression.push(Element::Operateur(operateur));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
autre => {
|
||||||
|
if !format_de_variable(autre) {
|
||||||
|
return Err(ErreurPendragon::MauvaisArgument(format!("{}", autre)))
|
||||||
|
}
|
||||||
|
self.programme.variable_est_de_type(autre, TypeElement::Booleen)?;
|
||||||
|
expression.push(Element::Variable(autre.into(), TypeElement::Booleen));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut index = 0;
|
while let Some(operateur) = pile_operateurs.pop() {
|
||||||
while index < expression.len() {
|
expression.push(Element::Operateur(operateur));
|
||||||
if expression[index] != "non" {
|
|
||||||
index += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if index == expression.len() - 1 {
|
|
||||||
return Err(ErreurPendragon::ManqueArgument);
|
|
||||||
}
|
|
||||||
let a = self.texte_comme_booleen(&expression[index + 1])?;
|
|
||||||
expression[index] = booleen_comme_texte(!a);
|
|
||||||
expression.remove(index + 1);
|
|
||||||
}
|
}
|
||||||
let mut index = 0;
|
|
||||||
while index < expression.len() {
|
|
||||||
if expression[index] != "et" {
|
|
||||||
index += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if index == 0 || index == expression.len() - 1 {
|
|
||||||
return Err(ErreurPendragon::ManqueArgument);
|
|
||||||
}
|
|
||||||
let a = self.texte_comme_booleen(&expression[index - 1])?;
|
|
||||||
let b = self.texte_comme_booleen(&expression[index + 1])?;
|
|
||||||
index -= 1;
|
|
||||||
expression[index] = booleen_comme_texte(a && b);
|
|
||||||
expression.remove(index + 1);
|
|
||||||
expression.remove(index + 1);
|
|
||||||
}
|
|
||||||
let mut index = 0;
|
|
||||||
while index < expression.len() {
|
|
||||||
if expression[index] != "ou" {
|
|
||||||
index += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if index == 0 || index == expression.len() - 1 {
|
|
||||||
return Err(ErreurPendragon::ManqueArgument);
|
|
||||||
}
|
|
||||||
let a = self.texte_comme_booleen(&expression[index - 1])?;
|
|
||||||
let b = self.texte_comme_booleen(&expression[index + 1])?;
|
|
||||||
index -= 1;
|
|
||||||
expression[index] = booleen_comme_texte(a || b);
|
|
||||||
expression.remove(index + 1);
|
|
||||||
expression.remove(index + 1);
|
|
||||||
}
|
|
||||||
if expression.len() > 1 {
|
|
||||||
return Err(ErreurPendragon::MauvaisArgument("expression booléenne".to_string()))
|
|
||||||
}
|
|
||||||
self.texte_comme_booleen(&expression[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn texte_comme_booleen(&self, texte: &str) -> Result<bool, ErreurPendragon> {
|
Ok(expression)
|
||||||
if texte.chars().next().map_or(false, |c| c.is_uppercase()) {
|
}
|
||||||
if self.variables.contains_key(texte) {
|
}
|
||||||
let Element::Booleen(booleen) = self.variables[texte] else {
|
|
||||||
return Err(ErreurPendragon::MauvaisType(texte.into(), self.variables[texte].type_element().nom(), "booleen".into()))
|
pub fn affiche_booleen(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<String, ErreurPendragon> {
|
||||||
};
|
let booleen = calcule_booleen(expression.clone(), variables)?;
|
||||||
return Ok(booleen);
|
Ok(booleen_comme_texte(booleen))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calcule_booleen(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<bool, ErreurPendragon> {
|
||||||
|
let mut pile: Vec<bool> = Vec::new();
|
||||||
|
|
||||||
|
for element in expression {
|
||||||
|
if let Element::Booleen(booleen) = element {
|
||||||
|
pile.push(booleen);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Element::Variable(nom, _) = element {
|
||||||
|
let Some(variable) = variables.get(&nom) else {
|
||||||
|
return Err(ErreurPendragon::VariableInconnue(nom.into()))
|
||||||
|
};
|
||||||
|
if let Element::Booleen(booleen) = variable {
|
||||||
|
pile.push(*booleen);
|
||||||
|
continue
|
||||||
} else {
|
} else {
|
||||||
return Err(ErreurPendragon::VariableInconnue(texte.to_string()))
|
return Err(ErreurPendragon::MauvaisType(nom.into(), variable.type_element().nom(), "booleen".into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
texte_comme_booleen(texte)
|
let Element::Operateur(ref operateur) = element else {
|
||||||
|
return Err(ErreurPendragon::MauvaisArgument(format!("{:?}, attendais un opérateur", element)))
|
||||||
|
};
|
||||||
|
let Some(booleen_a) = pile.pop() else {
|
||||||
|
return Err(ErreurPendragon::CalculBooleen("la pile est vide".into()))
|
||||||
|
};
|
||||||
|
match operateur {
|
||||||
|
Operateur::Non => {
|
||||||
|
pile.push(!booleen_a);
|
||||||
|
}
|
||||||
|
Operateur::Et => {
|
||||||
|
let Some(booleen_b) = pile.pop() else {
|
||||||
|
return Err(ErreurPendragon::CalculBooleen("la pile est vide".into()))
|
||||||
|
};
|
||||||
|
pile.push(booleen_a && booleen_b);
|
||||||
|
}
|
||||||
|
Operateur::Ou => {
|
||||||
|
let Some(booleen_b) = pile.pop() else {
|
||||||
|
return Err(ErreurPendragon::CalculBooleen("la pile est vide".into()))
|
||||||
|
};
|
||||||
|
pile.push(booleen_a || booleen_b);
|
||||||
|
}
|
||||||
|
_ => return Err(ErreurPendragon::MauvaisArgument(format!("{:?}, attendais un opérateur booléen", element)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if pile.len() > 1 {
|
||||||
|
return Err(ErreurPendragon::CalculBooleen("la pile n'est pas vide".into()))
|
||||||
|
}
|
||||||
|
Ok(pile[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn booleen_comme_texte(booleen: bool) -> String {
|
pub fn booleen_comme_texte(booleen: bool) -> String {
|
||||||
|
@ -84,10 +124,10 @@ pub fn booleen_comme_texte(booleen: bool) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn texte_comme_booleen(texte: &str) -> Result<bool, ErreurPendragon> {
|
pub fn texte_comme_booleen(texte: &str) -> Result<Element, ErreurPendragon> {
|
||||||
match texte {
|
match texte {
|
||||||
"vrai" => Ok(true),
|
"vrai" => Ok(Element::Booleen(true)),
|
||||||
"faux" => Ok(false),
|
"faux" => Ok(Element::Booleen(false)),
|
||||||
_ => Err(ErreurPendragon::BooleenInvalide(texte.into())),
|
_ => Err(ErreurPendragon::BooleenInvalide(texte.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
57
src/pendragon/debug.rs
Normal file
57
src/pendragon/debug.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
use std::fmt;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub enum ErreurPendragon {
|
||||||
|
CommandeInconnue(String),
|
||||||
|
ManqueArgument,
|
||||||
|
NombreInvalide(String),
|
||||||
|
BooleenInvalide(String),
|
||||||
|
TexteInvalide(String),
|
||||||
|
MauvaisArgument(String),
|
||||||
|
VariableInconnue(String),
|
||||||
|
MauvaisType(String, String, String),
|
||||||
|
ManquePoint,
|
||||||
|
Lecture(String),
|
||||||
|
CalculBooleen(String),
|
||||||
|
CalculEntier(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ErreurPendragon {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
||||||
|
match self {
|
||||||
|
Self::CommandeInconnue(commande) => write!(f, "La commande \"{}\" est inconnue.", commande),
|
||||||
|
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::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::ManquePoint => write!(f, "Il manque un point."),
|
||||||
|
Self::Lecture(raison) => write!(f, "Lecture d'entrées utilisateur impossible : {}.", raison),
|
||||||
|
Self::CalculBooleen(raison) => write!(f, "Calcul booleen échoué, {}.", raison),
|
||||||
|
Self::CalculEntier(raison) => write!(f, "Calcul entier échoué, {}.", raison),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Commande {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
||||||
|
match self {
|
||||||
|
Self::Definis(nom, type_element) => write!(f, "Definis {} comme {}.", nom, type_element.nom()),
|
||||||
|
Self::Demande(nom) => write!(f, "Demande {}.", nom),
|
||||||
|
Self::Modifie(nom, expression) => write!(f, "Modifie {} avec {:?}.", nom, expression),
|
||||||
|
Self::Affiche(expression) => write!(f, "Affiche {:?}.", expression),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Programme {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
||||||
|
let mut texte: String = format!("variables : {:?}", self.variables);
|
||||||
|
for (index, commande) in self.commandes.iter().enumerate() {
|
||||||
|
texte += &format!("\n#{:2}-{}", index+1, commande);
|
||||||
|
}
|
||||||
|
write!(f, "{}", texte)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
use std::io;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub mod nombre;
|
pub mod nombre;
|
||||||
|
@ -6,160 +5,113 @@ pub mod texte;
|
||||||
pub mod booleen;
|
pub mod booleen;
|
||||||
pub mod structure;
|
pub mod structure;
|
||||||
use structure::*;
|
use structure::*;
|
||||||
|
pub mod debug;
|
||||||
|
use debug::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub struct Pendragon {
|
pub struct Pendragon {
|
||||||
variables: HashMap<String, Element>,
|
pub programme: Programme,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pendragon {
|
impl Pendragon {
|
||||||
pub fn new() -> Self {
|
pub fn nouveau() -> Self {
|
||||||
Self {
|
Self {
|
||||||
variables: HashMap::new(),
|
programme: Programme::nouveau(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn compile(&mut self, contenu: String) -> Result<Vec<Commande>, ErreurPendragon> {
|
|
||||||
|
pub fn compile(&mut self, contenu: String) -> Result<(), ErreurPendragon> {
|
||||||
let contenu_propre = contenu.replace("\n", "");
|
let contenu_propre = contenu.replace("\n", "");
|
||||||
let mut texte: Vec<&str> = contenu_propre.split('.').collect();
|
let mut texte: Vec<&str> = contenu_propre.split('.').collect();
|
||||||
let reste = texte.pop();
|
let reste = texte.pop();
|
||||||
if reste != Some("") {
|
if reste != Some("") {
|
||||||
eprintln!("Erreur phrase {} : Il manque un point.", texte.len() + 1);
|
eprintln!("Erreur Compilation, phrase {} : Il manque un point.", texte.len() + 1);
|
||||||
return Err(ErreurPendragon::ManquePoint)
|
return Err(ErreurPendragon::ManquePoint)
|
||||||
}
|
}
|
||||||
let mut liste_commandes = Vec<Commande> = vec![];
|
|
||||||
for (index_phrase, phrase) in texte.iter().enumerate() {
|
for (index_phrase, phrase) in texte.iter().enumerate() {
|
||||||
match self.compile_phrase(phrase) {
|
match self.compile_phrase(phrase) {
|
||||||
Ok(commande) => {liste_commandes.push(commande)},
|
Ok(commande) => {self.programme.ajoute_commande(commande)},
|
||||||
Err(raison) => {
|
Err(raison) => {
|
||||||
eprintln!("Erreur phrase {} : {}", index_phrase + 1, raison);
|
eprintln!("Erreur phrase {} : {}", index_phrase + 1, raison);
|
||||||
return Err(raison)
|
return Err(raison)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(liste_commande)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_phrase(&self, phrase: &str) -> Result<Commande, ErreurPendragon> {
|
fn compile_phrase(&mut self, phrase: &str) -> Result<Commande, ErreurPendragon> {
|
||||||
let phrase = phrase.trim();
|
let phrase = phrase.trim();
|
||||||
let parties: Vec<&str> = phrase.splitn(2, ' ').collect();
|
let parties: Vec<&str> = phrase.splitn(2, ' ').collect();
|
||||||
|
if parties.len() == 1 {
|
||||||
|
return Err(ErreurPendragon::ManqueArgument)
|
||||||
|
}
|
||||||
match parties[0] {
|
match parties[0] {
|
||||||
"Définis" => {
|
"Définis" => self.definis(parties[1]),
|
||||||
self.definis(parties[1])
|
"Modifie" => self.modifie(parties[1]),
|
||||||
},
|
"Affiche" => self.affiche(parties[1]),
|
||||||
"Modifie" => {
|
"Demande" => self.demande(parties[1]),
|
||||||
self.modifie(parties[1])
|
autre => Err(ErreurPendragon::CommandeInconnue(autre.into())),
|
||||||
},
|
|
||||||
"Affiche" => {
|
|
||||||
self.affiche(parties[1])
|
|
||||||
},
|
|
||||||
"Demande" => {
|
|
||||||
self.demande(parties[1])
|
|
||||||
}
|
|
||||||
autre_commande => {
|
|
||||||
return Err(ErreurPendragon::CommandeInconnue(autre_commande.to_string()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn affiche(&self, arguments: &str) -> Result<Commande, ErreurPendragon> {
|
fn affiche(&self, arguments: &str) -> Result<Commande, ErreurPendragon> {
|
||||||
println!("{}", self.texte(arguments)?);
|
Ok(Commande::Affiche(self.elements_texte(arguments)?))
|
||||||
|
|
||||||
let commande = Affiche(Expression::avec_arguments(TypeElement::Texte, arguments)?)
|
|
||||||
Ok(commande)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn definis(&mut self, arguments: &str) -> Result<Commande, ErreurPendragon> {
|
fn definis(&mut self, arguments: &str) -> Result<Commande, ErreurPendragon> {
|
||||||
let (variable_nom, variable_type) = self.nom_de_variable(arguments, "comme")?;
|
let (variable_nom, variable_type_texte) = nom_de_variable(arguments, "comme")?;
|
||||||
|
let variable_type = TypeElement::texte_comme_type(&variable_type_texte)?;
|
||||||
|
|
||||||
let possible_variable = self.recupere_variable(&variable_nom);
|
self.programme.ajoute_variable(variable_nom.clone(), variable_type.clone())?;
|
||||||
|
|
||||||
let Err(raison) = possible_variable else {
|
Ok(Commande::Definis(variable_nom.into(), variable_type))
|
||||||
return Err(ErreurPendragon::MauvaisArgument(format!("la variable \"{}\" existe déjà", variable_nom)))
|
|
||||||
};
|
|
||||||
let ErreurPendragon::VariableInconnue(_) = raison else {
|
|
||||||
return Err(raison)
|
|
||||||
};
|
|
||||||
|
|
||||||
let contenu = match variable_type.as_str() {
|
|
||||||
"entier" => Element::Entier(0),
|
|
||||||
"texte" => Element::Texte("".to_string()),
|
|
||||||
"booléen" => Element::Booleen(false),
|
|
||||||
_ => return Err(ErreurPendragon::MauvaisArgument(format!("type de variable \"{}\" inconnu", variable_type))),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.variables.insert(variable_nom, contenu);
|
|
||||||
|
|
||||||
let commande = Definis(variable_nom.into(), contenu.type_element());
|
|
||||||
Ok(commande)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modifie(&mut self, arguments: &str) -> Result<Commande, ErreurPendragon> {
|
fn modifie(&mut self, arguments: &str) -> Result<Commande, ErreurPendragon> {
|
||||||
let (variable_nom, contenu) = self.nom_de_variable(arguments, "avec")?;
|
let (variable_nom, contenu) = nom_de_variable(arguments, "avec")?;
|
||||||
let variable = self.recupere_variable(&variable_nom)?;
|
let variable = self.programme.variable(&variable_nom)?;
|
||||||
|
|
||||||
let valeur = match variable.type_element() {
|
|
||||||
TypeElement::Entier => Element::Entier(self.operation(&contenu)?),
|
|
||||||
TypeElement::Texte => Element::Texte(self.texte(&contenu)?),
|
|
||||||
TypeElement::Booleen => Element::Booleen(self.condition(&contenu)?),
|
|
||||||
};
|
|
||||||
self.variables.insert(variable_nom, valeur);
|
|
||||||
|
|
||||||
let commande = Modifie(variable_nom, Expression::avec_arguments(variable.type_element(), arguments)?),
|
let elements = match variable {
|
||||||
Ok(commande)
|
TypeElement::Entier => self.elements_nombre(&contenu)?,
|
||||||
|
TypeElement::Texte => self.elements_texte(&contenu)?,
|
||||||
|
TypeElement::Booleen => self.elements_booleen(&contenu)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Commande::Modifie(variable_nom, elements))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn demande(&mut self, arguments: &str) -> Result<Commande, ErreurPendragon> {
|
fn demande(&mut self, arguments: &str) -> Result<Commande, ErreurPendragon> {
|
||||||
let (variable_nom, _) = self.nom_de_variable(arguments, "")?;
|
let (variable_nom, _) = nom_de_variable(arguments, "")?;
|
||||||
|
let _ = self.programme.variable(&variable_nom)?;
|
||||||
|
|
||||||
let _ = self.recupere_variable(&variable_nom)?;
|
Ok(Commande::Demande(variable_nom.into()))
|
||||||
|
|
||||||
println!("Quelle valeur pour {} ?", variable_nom);
|
|
||||||
let mut reponse: String = String::new();
|
|
||||||
if let Err(_) = io::stdin().read_line(&mut reponse) {
|
|
||||||
return Err(ErreurPendragon::ProblemeTerminal("lecture d'entrées utilisateur impossible".into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
let contenu = reponse.trim();
|
|
||||||
|
|
||||||
let valeur = match self.variables[&variable_nom].type_element() {
|
|
||||||
TypeElement::Entier => Element::Entier(nombre::texte_comme_nombre(contenu)?),
|
|
||||||
TypeElement::Texte => Element::Texte(contenu.into()),
|
|
||||||
TypeElement::Booleen => Element::Booleen(booleen::texte_comme_booleen(contenu)?)
|
|
||||||
};
|
|
||||||
self.variables.insert(variable_nom, valeur);
|
|
||||||
|
|
||||||
let commande = Demande(variable_nom.into());
|
|
||||||
Ok(commande)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recupere_variable(&self, nom: &str) -> Result<Element, ErreurPendragon> {
|
|
||||||
let Some(first_char) = nom.chars().next() else {
|
|
||||||
return Err(ErreurPendragon::MauvaisArgument("il n'y a pas de variable".to_string()))
|
|
||||||
};
|
|
||||||
if !first_char.is_uppercase() {
|
|
||||||
return Err(ErreurPendragon::MauvaisArgument("il manque une majuscule à la variable".to_string()))
|
|
||||||
}
|
|
||||||
if !self.variables.contains_key(nom) {
|
|
||||||
return Err(ErreurPendragon::VariableInconnue(nom.into()))
|
|
||||||
}
|
|
||||||
Ok(self.variables[nom].clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nom_de_variable(&self, arguments: &str, separateur: &str) -> Result<(String, String), ErreurPendragon> {
|
|
||||||
let parties = if separateur == "" {
|
|
||||||
vec![arguments, ""]
|
|
||||||
} else {
|
|
||||||
arguments.splitn(2, separateur).collect()
|
|
||||||
};
|
|
||||||
|
|
||||||
let nom_variable = parties[0].trim().to_string();
|
|
||||||
|
|
||||||
if parties.len() == 1 {
|
|
||||||
return Err(ErreurPendragon::ManqueArgument)
|
|
||||||
}
|
|
||||||
Ok((nom_variable, parties[1].trim().to_string()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn nom_de_variable(arguments: &str, separateur: &str) -> Result<(String, String), ErreurPendragon> {
|
||||||
|
let parties = if separateur == "" {
|
||||||
|
vec![arguments, ""]
|
||||||
|
} else {
|
||||||
|
arguments.splitn(2, separateur).collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
let nom_variable = parties[0].trim().to_string();
|
||||||
|
|
||||||
|
if parties.len() == 1 {
|
||||||
|
return Err(ErreurPendragon::ManqueArgument)
|
||||||
|
}
|
||||||
|
Ok((nom_variable, parties[1].trim().to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_de_variable(nom: &str) -> bool {
|
||||||
|
let Some(first_char) = nom.chars().next() else {
|
||||||
|
return false
|
||||||
|
};
|
||||||
|
if !first_char.is_uppercase() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use super::ErreurPendragon;
|
use super::*;
|
||||||
use super::Pendragon;
|
|
||||||
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"];
|
||||||
|
@ -9,107 +7,138 @@ const NOMS_SEPARATEURS: [&str; 7] = ["", "mille", "million", "milliard", "billio
|
||||||
const UNION: &str = "-";
|
const UNION: &str = "-";
|
||||||
|
|
||||||
impl Pendragon {
|
impl Pendragon {
|
||||||
pub fn operation(&self, arguments: &str) -> Result<usize, ErreurPendragon> {
|
pub fn elements_nombre(&self, arguments: &str) -> Result<Vec<Element>, ErreurPendragon> {
|
||||||
//return self.operation_elementaire(arguments);
|
|
||||||
let texte = arguments
|
let texte = arguments
|
||||||
.replace("ouvre la parenthèse", "ouvre-la-parenthese")
|
.replace("ouvre la parenthèse", "ouvre-la-parenthese")
|
||||||
.replace("ferme la parenthèse", "ferme-la-parenthese")
|
.replace("ferme la parenthèse", "ferme-la-parenthese")
|
||||||
.replace("divisé par", "divise-par");
|
.replace("divisé par", "divise-par");
|
||||||
let mut expression: Vec<String> = texte.split(" ").map(String::from).collect();
|
let elements_texte: Vec<&str> = texte.split(" ").collect();
|
||||||
|
let mut expression: Vec<Element> = Vec::new();
|
||||||
|
let mut pile_operateurs: Vec<Operateur> = Vec::new();
|
||||||
|
|
||||||
|
for element in elements_texte {
|
||||||
|
match element {
|
||||||
|
"plus" => {
|
||||||
|
while let Some(operateur) = pile_operateurs.last() {
|
||||||
|
if *operateur == Operateur::Plus || *operateur == Operateur::Moins || *operateur == Operateur::Fois || *operateur == Operateur::Divise {
|
||||||
|
expression.push(Element::Operateur(pile_operateurs.pop().unwrap()));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pile_operateurs.push(Operateur::Plus);
|
||||||
|
}
|
||||||
|
"moins" => {
|
||||||
|
while let Some(operateur) = pile_operateurs.last() {
|
||||||
|
if *operateur == Operateur::Plus || *operateur == Operateur::Moins || *operateur == Operateur::Fois || *operateur == Operateur::Divise {
|
||||||
|
expression.push(Element::Operateur(pile_operateurs.pop().unwrap()));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pile_operateurs.push(Operateur::Moins);
|
||||||
|
}
|
||||||
|
"fois" => {
|
||||||
|
while let Some(operateur) = pile_operateurs.last() {
|
||||||
|
if *operateur == Operateur::Fois || *operateur == Operateur::Divise {
|
||||||
|
expression.push(Element::Operateur(pile_operateurs.pop().unwrap()));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pile_operateurs.push(Operateur::Fois);
|
||||||
|
}
|
||||||
|
"divise-par" => {
|
||||||
|
while let Some(operateur) = pile_operateurs.last() {
|
||||||
|
if *operateur == Operateur::Fois || *operateur == Operateur::Divise {
|
||||||
|
expression.push(Element::Operateur(pile_operateurs.pop().unwrap()));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pile_operateurs.push(Operateur::Divise);
|
||||||
|
}
|
||||||
|
"ouvre-la-parenthese" => pile_operateurs.push(Operateur::ParentheseEntier),
|
||||||
|
"ferme-la-parenthese" => {
|
||||||
|
while let Some(operateur) = pile_operateurs.pop() {
|
||||||
|
if operateur == Operateur::ParentheseEntier {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
expression.push(Element::Operateur(operateur));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
autre => {
|
||||||
|
if format_de_variable(autre) {
|
||||||
|
self.programme.variable_est_de_type(autre, TypeElement::Entier)?;
|
||||||
|
expression.push(Element::Variable(autre.into(), TypeElement::Entier));
|
||||||
|
} else {
|
||||||
|
expression.push(texte_comme_nombre(autre)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while expression.contains(&"ouvre-la-parenthese".to_string()) {
|
while let Some(operateur) = pile_operateurs.pop() {
|
||||||
let mut ouverture: Option<usize> = None;
|
expression.push(Element::Operateur(operateur));
|
||||||
let mut fermeture: Option<usize> = None;
|
|
||||||
for index in 0..expression.len() {
|
|
||||||
if expression[index] == "ouvre-la-parenthese" {
|
|
||||||
ouverture = Some(index);
|
|
||||||
}
|
|
||||||
if expression[index] == "ferme-la-parenthese" && ouverture.is_some() {
|
|
||||||
fermeture = Some(index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let Some(index_ouverture) = ouverture else {
|
|
||||||
return Err(ErreurPendragon::DesequilibreParenthese);
|
|
||||||
};
|
|
||||||
let Some(index_fermeture) = fermeture else {
|
|
||||||
return Err(ErreurPendragon::DesequilibreParenthese);
|
|
||||||
};
|
|
||||||
let contenu: String = expression[(index_ouverture+1)..(index_fermeture)].join(" ");
|
|
||||||
let nombre = self.operation_elementaire(&contenu)?;
|
|
||||||
let nombre_texte = nombre_comme_texte(nombre);
|
|
||||||
expression[index_ouverture] = nombre_texte;
|
|
||||||
for _ in 0..(index_fermeture-index_ouverture) {
|
|
||||||
expression.remove(index_ouverture+1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if expression.contains(&"ferme-la-parenthese".to_string()) {
|
|
||||||
return Err(ErreurPendragon::DesequilibreParenthese);
|
Ok(expression)
|
||||||
}
|
|
||||||
self.operation_elementaire(&expression.join(" "))
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn operation_elementaire(&self, arguments: &str) -> Result<usize, ErreurPendragon> {
|
pub fn affiche_nombre(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<String, ErreurPendragon> {
|
||||||
let texte = arguments.replace("divisé par", "divise-par");
|
let nombre = calcule_nombre(expression.clone(), variables)?;
|
||||||
let mut expression: Vec<String> = texte.split(" ").map(String::from).collect();
|
Ok(nombre_comme_texte(nombre))
|
||||||
|
}
|
||||||
|
|
||||||
let mut index = 0;
|
pub fn calcule_nombre(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<usize, ErreurPendragon> {
|
||||||
while index < expression.len() {
|
let mut pile: Vec<usize> = Vec::new();
|
||||||
if expression[index] != "fois" && expression[index] != "divise-par" {
|
|
||||||
index += 1;
|
for element in expression {
|
||||||
continue;
|
if let Element::Entier(nombre) = element {
|
||||||
}
|
pile.push(nombre);
|
||||||
if index == 0 || index == expression.len() - 1 {
|
continue;
|
||||||
return Err(ErreurPendragon::ManqueArgument);
|
|
||||||
}
|
|
||||||
let a = self.texte_comme_nombre(&expression[index - 1])?;
|
|
||||||
let b = self.texte_comme_nombre(&expression[index + 1])?;
|
|
||||||
let produit = if expression[index] == "fois" {a*b} else {a/b};
|
|
||||||
let produit_texte: String = nombre_comme_texte(produit);
|
|
||||||
index -= 1;
|
|
||||||
expression[index] = produit_texte;
|
|
||||||
expression.remove(index + 1);
|
|
||||||
expression.remove(index + 1);
|
|
||||||
}
|
}
|
||||||
|
if let Element::Variable(nom, _) = element {
|
||||||
let mut index = 0;
|
let Some(variable) = variables.get(&nom) else {
|
||||||
while index < expression.len() {
|
return Err(ErreurPendragon::VariableInconnue(nom.into()))
|
||||||
if expression[index] != "plus" && expression[index] != "moins" {
|
};
|
||||||
index += 1;
|
if let Element::Entier(nombre) = variable {
|
||||||
continue;
|
pile.push(*nombre);
|
||||||
}
|
continue
|
||||||
if index == 0 || index == expression.len() - 1 {
|
|
||||||
return Err(ErreurPendragon::ManqueArgument);
|
|
||||||
}
|
|
||||||
let a = self.texte_comme_nombre(&expression[index - 1])?;
|
|
||||||
let b = self.texte_comme_nombre(&expression[index + 1])?;
|
|
||||||
let somme = if expression[index] == "plus" {a+b} else {a-b};
|
|
||||||
let somme_texte: String = nombre_comme_texte(somme);
|
|
||||||
index -= 1;
|
|
||||||
expression[index] = somme_texte;
|
|
||||||
expression.remove(index + 1);
|
|
||||||
expression.remove(index + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if expression.len() > 1 {
|
|
||||||
return Err(ErreurPendragon::MauvaisArgument("expression mathématique".to_string()))
|
|
||||||
}
|
|
||||||
self.texte_comme_nombre(&expression[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn texte_comme_nombre(&self, texte: &str) -> Result<usize, ErreurPendragon> {
|
|
||||||
if texte.chars().next().map_or(false, |c| c.is_uppercase()) {
|
|
||||||
if self.variables.contains_key(texte) {
|
|
||||||
let Element::Entier(nombre) = self.variables[texte] else {
|
|
||||||
return Err(ErreurPendragon::MauvaisType(texte.into(), self.variables[texte].type_element().nom(), "entier".into()))
|
|
||||||
};
|
|
||||||
return Ok(nombre);
|
|
||||||
} else {
|
} else {
|
||||||
return Err(ErreurPendragon::VariableInconnue(texte.to_string()))
|
return Err(ErreurPendragon::MauvaisType(nom.into(), variable.type_element().nom(), "entier".into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
texte_comme_nombre(texte)
|
let Element::Operateur(ref operateur) = element else {
|
||||||
|
return Err(ErreurPendragon::MauvaisArgument(format!("{:?}, attendais un opérateur", element)))
|
||||||
|
};
|
||||||
|
let Some(nombre_a) = pile.pop() else {
|
||||||
|
return Err(ErreurPendragon::CalculEntier("la pile est vide".into()))
|
||||||
|
};
|
||||||
|
let Some(nombre_b) = pile.pop() else {
|
||||||
|
return Err(ErreurPendragon::CalculEntier("la pile est vide".into()))
|
||||||
|
};
|
||||||
|
match operateur {
|
||||||
|
Operateur::Plus => {
|
||||||
|
pile.push(nombre_b + nombre_b);
|
||||||
|
}
|
||||||
|
Operateur::Moins => {
|
||||||
|
pile.push(nombre_b - nombre_a);
|
||||||
|
}
|
||||||
|
Operateur::Fois => {
|
||||||
|
pile.push(nombre_b * nombre_a);
|
||||||
|
}
|
||||||
|
Operateur::Divise => {
|
||||||
|
pile.push(nombre_b / nombre_a);
|
||||||
|
}
|
||||||
|
_ => return Err(ErreurPendragon::MauvaisArgument(format!("{:?}, attendais un opérateur d'entiers", element)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if pile.len() > 1 {
|
||||||
|
return Err(ErreurPendragon::CalculEntier("la pile n'est pas vide".into()))
|
||||||
|
}
|
||||||
|
Ok(pile[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nombre_comme_texte(nombre: usize) -> String {
|
pub fn nombre_comme_texte(nombre: usize) -> String {
|
||||||
|
@ -198,9 +227,9 @@ fn petit_nombre_comme_texte(nombre: usize) -> String {
|
||||||
format!("{}{}{}{}{}", centaine_texte, dizaine_union, dizaine_texte, séparation, unité_texte)
|
format!("{}{}{}{}{}", centaine_texte, dizaine_union, dizaine_texte, séparation, unité_texte)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn texte_comme_nombre(texte: &str) -> Result<usize, ErreurPendragon> {
|
pub fn texte_comme_nombre(texte: &str) -> Result<Element, ErreurPendragon> {
|
||||||
if texte == "zéro" {
|
if texte == "zéro" {
|
||||||
return Ok(0)
|
return Ok(Element::Entier(0))
|
||||||
}
|
}
|
||||||
let pluriel = format!("s{}", UNION);
|
let pluriel = format!("s{}", UNION);
|
||||||
let mut petits_nombres_texte: Vec<&str> = vec![];
|
let mut petits_nombres_texte: Vec<&str> = vec![];
|
||||||
|
@ -243,7 +272,7 @@ pub fn texte_comme_nombre(texte: &str) -> Result<usize, ErreurPendragon> {
|
||||||
nombre += petit_nombre * 1000usize.pow((petits_nombres_texte.len() - index - 1) as u32);
|
nombre += petit_nombre * 1000usize.pow((petits_nombres_texte.len() - index - 1) as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(nombre)
|
Ok(Element::Entier(nombre))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn texte_comme_petit_nombre(texte: &str) -> Result<usize, ErreurPendragon> {
|
fn texte_comme_petit_nombre(texte: &str) -> Result<usize, ErreurPendragon> {
|
||||||
|
|
|
@ -1,43 +1,90 @@
|
||||||
use std::fmt;
|
use std::io;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct Programme {
|
||||||
|
pub variables: HashMap<String, TypeElement>,
|
||||||
|
pub commandes: Vec<Commande>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Programme {
|
||||||
|
pub fn nouveau() -> Self {
|
||||||
|
Self {
|
||||||
|
variables: HashMap::new(),
|
||||||
|
commandes: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ajoute_commande(&mut self, commande: Commande) {
|
||||||
|
self.commandes.push(commande);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ajoute_variable(&mut self, nom: String, type_variable: TypeElement) -> Result<(), ErreurPendragon> {
|
||||||
|
let Err(raison) = self.variable(&nom) else {
|
||||||
|
return Err(ErreurPendragon::MauvaisArgument(format!("la variable \"{}\" existe déjà", nom)))
|
||||||
|
};
|
||||||
|
let ErreurPendragon::VariableInconnue(_) = raison else {
|
||||||
|
return Err(raison)
|
||||||
|
};
|
||||||
|
self.variables.insert(nom, type_variable);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variable(&self, nom: &str) -> Result<TypeElement, ErreurPendragon> {
|
||||||
|
let Some(first_char) = nom.chars().next() else {
|
||||||
|
return Err(ErreurPendragon::MauvaisArgument("il n'y a pas de variable".to_string()))
|
||||||
|
};
|
||||||
|
if !first_char.is_uppercase() {
|
||||||
|
return Err(ErreurPendragon::MauvaisArgument("il manque une majuscule à la variable".to_string()))
|
||||||
|
}
|
||||||
|
if !self.variables.contains_key(nom) {
|
||||||
|
return Err(ErreurPendragon::VariableInconnue(nom.into()))
|
||||||
|
}
|
||||||
|
Ok(self.variables[nom].clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variable_est_de_type(&self, nom: &str, type_element: TypeElement) -> Result<(), ErreurPendragon> {
|
||||||
|
let type_variable = self.variable(nom)?;
|
||||||
|
if type_variable != type_element {
|
||||||
|
return Err(ErreurPendragon::MauvaisType(nom.into(), type_variable.nom(), type_element.nom()))
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(&self) -> Result<(), ErreurPendragon> {
|
||||||
|
let mut variables_globales: HashMap<String, Element> = HashMap::new();
|
||||||
|
for commande in &self.commandes {
|
||||||
|
match commande {
|
||||||
|
Commande::Definis(nom, type_element) => {
|
||||||
|
variables_globales.insert(nom.to_string(), type_element.comme_element());
|
||||||
|
}
|
||||||
|
Commande::Demande(nom) => {
|
||||||
|
let valeur = variables_globales[nom].type_element().demande_valeur(&nom)?;
|
||||||
|
variables_globales.insert(nom.to_string(), valeur);
|
||||||
|
}
|
||||||
|
Commande::Modifie(nom, expression) => {
|
||||||
|
let valeur = match variables_globales[nom].type_element() {
|
||||||
|
TypeElement::Entier => Element::Entier(nombre::calcule_nombre(expression.clone(), &variables_globales)?),
|
||||||
|
TypeElement::Texte => Element::Texte(texte::calcule_texte(expression.clone(), &variables_globales)?),
|
||||||
|
TypeElement::Booleen => Element::Booleen(booleen::calcule_booleen(expression.clone(), &variables_globales)?),
|
||||||
|
};
|
||||||
|
variables_globales.insert(nom.to_string(), valeur);
|
||||||
|
}
|
||||||
|
Commande::Affiche(expression) => {
|
||||||
|
println!("{}", texte::calcule_texte(expression.to_vec(), &variables_globales)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Commande {
|
pub enum Commande {
|
||||||
Definis(String, TypeElement),
|
Definis(String, TypeElement),
|
||||||
Demande(String),
|
Demande(String),
|
||||||
Modifie(String, Expression),
|
Modifie(String, Vec<Element>),
|
||||||
Affiche(Expression),
|
Affiche(Vec<Element>),
|
||||||
}
|
|
||||||
|
|
||||||
#[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 avec_arguments(type_expression: TypeElement, arguments: &str) -> Result<Self, ErreurPendragon> {
|
|
||||||
let expression = Self {
|
|
||||||
type_expression,
|
|
||||||
contenu: vec![]
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ajoute(&mut self, element: Element) -> Result<(), ErreurPendragon> {
|
|
||||||
let type_element = element.type_element();
|
|
||||||
if self.type_expression != type_element {
|
|
||||||
return Err(ErreurPendragon::MauvaisType("inconnue".into(), type_element.nom(), self.type_expression.nom()))
|
|
||||||
}
|
|
||||||
self.contenu.push(element);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
@ -55,6 +102,47 @@ impl TypeElement {
|
||||||
Self::Booleen => "booléen".into(),
|
Self::Booleen => "booléen".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn texte_comme_type(texte: &str) -> Result<Self, ErreurPendragon> {
|
||||||
|
match texte.trim() {
|
||||||
|
"entier" => Ok(TypeElement::Entier),
|
||||||
|
"texte" => Ok(TypeElement::Texte),
|
||||||
|
"booléen" => Ok(TypeElement::Booleen),
|
||||||
|
autre => return Err(ErreurPendragon::MauvaisArgument(format!("type de variable \"{}\" inconnu", autre))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn comme_element(&self) -> Element {
|
||||||
|
match self {
|
||||||
|
Self::Entier => Element::Entier(0),
|
||||||
|
Self::Texte => Element::Texte("".into()),
|
||||||
|
Self::Booleen => Element::Booleen(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texte_comme_element(&self, texte: &str) -> Result<Element, ErreurPendragon> {
|
||||||
|
match self {
|
||||||
|
Self::Entier => nombre::texte_comme_nombre(texte),
|
||||||
|
Self::Texte => Ok(Element::Texte(texte.into())),
|
||||||
|
Self::Booleen => booleen::texte_comme_booleen(texte),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn demande_valeur(&self, nom: &str) -> Result<Element, ErreurPendragon> {
|
||||||
|
loop {
|
||||||
|
println!("Quelle valeur pour {} ({}) ?", nom, self.nom());
|
||||||
|
|
||||||
|
let mut reponse = String::new();
|
||||||
|
if let Err(raison) = io::stdin().read_line(&mut reponse) {
|
||||||
|
return Err(ErreurPendragon::Lecture(format!("{}", raison)));
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.texte_comme_element(reponse.trim()) {
|
||||||
|
Ok(element) => return Ok(element),
|
||||||
|
Err(raison) => eprintln!("Erreur : {}", raison),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
@ -63,8 +151,7 @@ pub enum Element {
|
||||||
Texte(String),
|
Texte(String),
|
||||||
Booleen(bool),
|
Booleen(bool),
|
||||||
Variable(String, TypeElement),
|
Variable(String, TypeElement),
|
||||||
Operateur(String, TypeElement),
|
Operateur(Operateur),
|
||||||
Expression(Expression, TypeElement),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element {
|
impl Element {
|
||||||
|
@ -74,42 +161,31 @@ impl Element {
|
||||||
Self::Texte(_) => TypeElement::Texte,
|
Self::Texte(_) => TypeElement::Texte,
|
||||||
Self::Booleen(_) => TypeElement::Booleen,
|
Self::Booleen(_) => TypeElement::Booleen,
|
||||||
Self::Variable(_, type_element) => type_element.clone(),
|
Self::Variable(_, type_element) => type_element.clone(),
|
||||||
Self::Operateur(_, type_element) => type_element.clone(),
|
Self::Operateur(operateur) => operateur.type_element(),
|
||||||
Self::Expression(_, type_element) => type_element.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ErreurPendragon {
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
CommandeInconnue(String),
|
pub enum Operateur {
|
||||||
PhraseVide,
|
Ou,
|
||||||
ManqueArgument,
|
Et,
|
||||||
NombreInvalide(String),
|
Non,
|
||||||
BooleenInvalide(String),
|
ParentheseBooleen,
|
||||||
TexteInvalide(String),
|
Virgule,
|
||||||
MauvaisArgument(String),
|
Plus,
|
||||||
DesequilibreParenthese,
|
Moins,
|
||||||
VariableInconnue(String),
|
Fois,
|
||||||
MauvaisType(String, String, String),
|
Divise,
|
||||||
ProblemeTerminal(String),
|
ParentheseEntier,
|
||||||
ManquePoint,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ErreurPendragon {
|
impl Operateur {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
pub fn type_element(&self) -> TypeElement {
|
||||||
match self {
|
match self {
|
||||||
Self::CommandeInconnue(commande) => write!(f, "La commande \"{}\" est inconnue.", commande),
|
Self::Ou | Self::Et | Self::Non | Self::ParentheseBooleen => TypeElement::Booleen,
|
||||||
Self::PhraseVide => write!(f, "La phrase est vide."),
|
Self::Virgule => TypeElement::Texte,
|
||||||
Self::ManqueArgument => write!(f, "Il manque un argument."),
|
Self::Plus | Self::Moins | Self::Fois | Self::Divise | Self::ParentheseEntier => TypeElement::Entier,
|
||||||
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."),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,44 +1,78 @@
|
||||||
use super::Pendragon;
|
use super::*;
|
||||||
use super::ErreurPendragon;
|
|
||||||
use super::Element;
|
|
||||||
use super::nombre;
|
|
||||||
use super::booleen;
|
|
||||||
|
|
||||||
impl Pendragon {
|
impl Pendragon {
|
||||||
pub fn texte(&self, arguments: &str) -> Result<String, ErreurPendragon> {
|
pub fn elements_texte(&self, arguments: &str) -> Result<Vec<Element>, ErreurPendragon> {
|
||||||
let liste_arguments: Vec<&str> = arguments.split(',').collect();
|
let mut expression: Vec<Element> = Vec::new();
|
||||||
|
|
||||||
let mut texte = "".to_string();
|
for argument in arguments.split(',').map(|arg| arg.trim()) {
|
||||||
|
if expression.len() > 0 {
|
||||||
for argument in liste_arguments {
|
expression.push(Element::Operateur(Operateur::Virgule));
|
||||||
let argument: &str = argument.trim();
|
}
|
||||||
if argument.starts_with('"') {
|
if argument.starts_with('"') {
|
||||||
if argument.ends_with('"') {
|
if argument.ends_with('"') {
|
||||||
texte += &argument[1..argument.len()-1];
|
expression.push(Element::Texte(argument[1..argument.len() - 1].into()));
|
||||||
} else {
|
} else {
|
||||||
return Err(ErreurPendragon::TexteInvalide("guillemet mal refermé".into()))
|
return Err(ErreurPendragon::TexteInvalide("guillemet mal refermé".into()))
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if format_de_variable(argument) && !argument.contains(" ") {
|
||||||
if let Ok(nombre) = self.operation(argument) {
|
expression.push(Element::Variable(argument.into(), self.programme.variable(argument)?));
|
||||||
texte += &nombre::nombre_comme_texte(nombre);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if let Ok(elements_nombre) = self.elements_nombre(argument) {
|
||||||
if let Ok(booleen) = self.condition(argument) {
|
expression.extend(elements_nombre);
|
||||||
texte += &booleen::booleen_comme_texte(booleen);
|
} else if let Ok(elements_booleen) = self.elements_booleen(argument) {
|
||||||
continue;
|
expression.extend(elements_booleen);
|
||||||
|
} else {
|
||||||
|
return Err(ErreurPendragon::MauvaisArgument(argument.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let variable = self.recupere_variable(argument)?;
|
|
||||||
|
|
||||||
let Element::Texte(contenu) = variable else {
|
|
||||||
return Err(ErreurPendragon::MauvaisType(argument.into(), variable.type_element().nom(), "texte".into()))
|
|
||||||
};
|
|
||||||
|
|
||||||
texte += &contenu;
|
|
||||||
}
|
}
|
||||||
Ok(texte)
|
expression.push(Element::Operateur(Operateur::Virgule));
|
||||||
|
Ok(expression)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calcule_texte(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<String, ErreurPendragon> {
|
||||||
|
let mut pile: Vec<Element> = Vec::new();
|
||||||
|
let mut texte: String = String::new();
|
||||||
|
|
||||||
|
for element in expression {
|
||||||
|
let Element::Operateur(ref operateur) = element else {
|
||||||
|
pile.push(element);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Operateur::Virgule = operateur else {
|
||||||
|
pile.push(element);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(element_pile) = pile.last() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if let TypeElement::Booleen = element_pile.type_element() {
|
||||||
|
texte += &booleen::affiche_booleen(pile.clone(), variables)?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let TypeElement::Entier = element_pile.type_element() {
|
||||||
|
texte += &nombre::affiche_nombre(pile.clone(), variables)?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match element_pile {
|
||||||
|
Element::Texte(contenu) => texte += contenu,
|
||||||
|
Element::Variable(nom, type_element) => {
|
||||||
|
let Some(variable) = variables.get(nom) else {
|
||||||
|
return Err(ErreurPendragon::VariableInconnue(nom.into()))
|
||||||
|
};
|
||||||
|
let Element::Texte(contenu) = variable else {
|
||||||
|
return Err(ErreurPendragon::MauvaisType(nom.into(), type_element.nom(), "texte".into()))
|
||||||
|
};
|
||||||
|
texte += &contenu;
|
||||||
|
}
|
||||||
|
autre => {
|
||||||
|
return Err(ErreurPendragon::MauvaisArgument(format!("{:?}", autre)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pile = Vec::new();
|
||||||
|
}
|
||||||
|
Ok(texte)
|
||||||
}
|
}
|
14
test.dr
14
test.dr
|
@ -1,7 +1,9 @@
|
||||||
Définis A comme entier.
|
|
||||||
Modifie A avec mille-cinq-cent-cinquante-cinq fois treize.
|
|
||||||
Affiche A.
|
|
||||||
Définis B comme booléen.
|
Définis B comme booléen.
|
||||||
Affiche "B ou : ", B ou vrai.
|
Définis C comme booléen.
|
||||||
Affiche "B et : ", B et vrai.
|
Définis D comme booléen.
|
||||||
Affiche dix fois dix fois dix.
|
Modifie B avec vrai et ouvre la parenthèse non C ou D ferme la parenthèse ou faux.
|
||||||
|
Affiche "B : ", B.
|
||||||
|
Définis E comme entier.
|
||||||
|
Modifie E avec mille-cinq-cent-cinquante-cinq fois ouvre la parenthèse un plus six ferme la parenthèse plus quarante-deux.
|
||||||
|
Affiche mille-cinq-cent-cinquante-cinq fois ouvre la parenthèse un plus six ferme la parenthèse plus quarante-deux.
|
||||||
|
Affiche "E : ", E fois dix.
|
Loading…
Reference in a new issue