diff --git a/pendragon.project b/pendragon.project index b685190..dcccd75 100644 --- a/pendragon.project +++ b/pendragon.project @@ -1,2 +1 @@ -{"categories":[{"name":"todo","content":[{"name":"commentaires","description":"// Hello there","id":3},{"name":"compile time verification","description":"odre des termes rpn","id":1},{"name":"error context","description":"// Hello there","id":2},{"name":"test correct error","description":"// Hello there","id":3},{"name":"if","description":"implémente if avec des guillemets de délimitation","id":1},{"name":"scope variable","description":"// Hello there","id":6},{"name":"while","description":"implémente un while","id":2},{"name":"else","description":"// Hello there","id":7},{"name":"break","description":"// Hello there","id":8},{"name":"continue","description":"// Hello there","id":9},{"name":"compilation","description":"// Hello there","id":3}]},{"name":"in progress","content":[]},{"name":"done","content":[{"name":"comparaison","description":"// Hello there","id":2},{"name":"booleen type","description":"// Hello there","id":4},{"name":"soixante-dix","description":"// Hello there","id":1},{"name":"parenthese comparaison","description":"// Hello there","id":1},{"name":"test comparaison","description":"// Hello there","id":4}]},{"name":"bug","content":[]},{"name":"to test","content":[]},{"name":"bonus","content":[{"name":"stop cheating with \"-\"","description":"// Hello there","id":5}]},{"name":"+","content":[]}]} - +{"categories":[{"name":"todo","content":[{"name":"test correct error","description":"manque point\nmauvaise expression mathematique","id":3},{"name":"if","description":"implémente if avec des guillemets de délimitation","id":1},{"name":"scope variable","description":"// Hello there","id":6},{"name":"while","description":"implémente un while","id":2},{"name":"else","description":"// Hello there","id":7},{"name":"break","description":"// Hello there","id":8},{"name":"continue","description":"// Hello there","id":9},{"name":"compilation","description":"// Hello there","id":3}]},{"name":"in progress","content":[]},{"name":"done","content":[{"name":"comparaison","description":"// Hello there","id":2},{"name":"booleen type","description":"// Hello there","id":4},{"name":"soixante-dix","description":"// Hello there","id":1},{"name":"parenthese comparaison","description":"// Hello there","id":1},{"name":"test comparaison","description":"// Hello there","id":4},{"name":"error ligne compilation","description":"// Hello there","id":2},{"name":"commentaires","description":"// Hello there","id":3},{"name":"compile time verification","description":"odre des termes rpn","id":1}]},{"name":"bug","content":[]},{"name":"to test","content":[]},{"name":"bonus","content":[{"name":"stop cheating with \"-\"","description":"// Hello there","id":5},{"name":"affiche ligne et position erreur","description":"// Hello there","id":1}]},{"name":"+","content":[]}]} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 1f9c566..82a08fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,11 @@ use std::env; use std::fs; +use std::time::Instant; mod pendragon; use pendragon::*; -fn main() { +fn main() { let arguments: Vec = env::args().collect(); if arguments.len() < 2 { @@ -17,22 +18,34 @@ fn main() { let chemin_de_fichier = &arguments[1]; let mut pendragon = Pendragon::nouveau(); - match fs::read_to_string(chemin_de_fichier) { - Ok(contenu) => { - let Ok(_) = pendragon.compile(contenu) else { - eprintln!("\n# Échec de la compilation"); - return - }; - if debug_mode { - println!("{}\n", pendragon.programme); - } - if let Err(raison) = pendragon.programme.execute() { - eprintln!("Erreur Execution : {}", raison); - return - } - } - Err(raison) => { - eprintln!("Fichier illisible : {}", raison); - } + let lecture = fs::read_to_string(chemin_de_fichier); + + if let Err(raison) = lecture { + eprintln!("Fichier illisible : {}", raison); + return } + + println!("# Compilation de '{}'.", chemin_de_fichier); + let debut = Instant::now(); + if let Err(raison) = pendragon.compile(lecture.unwrap()) { + eprintln!("\n{}", raison); + eprintln!("\n# Échec de la compilation."); + return + } + println!("# Compilation Ok. ({:.2?})\n", debut.elapsed()); + + if debug_mode { + println!("{}\n", pendragon.programme); + } + + + println!("# Exécution de '{}'.\n", chemin_de_fichier); + let debut = Instant::now(); + if let Err(raison) = pendragon.programme.execute() { + eprintln!("\nErreur : {}", raison); + eprintln!("\n# Échec de l'exécution."); + return + } + + println!("\n# Exécution Ok. ({:.2?})", debut.elapsed()); } diff --git a/src/pendragon/booleen.rs b/src/pendragon/booleen.rs index e376939..03c0806 100644 --- a/src/pendragon/booleen.rs +++ b/src/pendragon/booleen.rs @@ -383,7 +383,7 @@ mod test { nombre::nombre_comme_texte(e), )); let bonne_reponse = !((6+a) > 2*b) && (c/2 < (d-1) || !(e == 2)); - match possible_expression{ + match possible_expression { Ok(expression) => { match calcule_booleen(expression.clone(), &HashMap::new()) { Ok(booleen) => { diff --git a/src/pendragon/debug.rs b/src/pendragon/debug.rs index ddd96ea..5490189 100644 --- a/src/pendragon/debug.rs +++ b/src/pendragon/debug.rs @@ -1,6 +1,27 @@ use std::fmt; use super::*; +pub struct ErreurCompilation { + index_ligne: usize, + erreur: ErreurPendragon, +} + +impl ErreurCompilation { + pub fn nouvelle(index_ligne: usize, erreur: ErreurPendragon) -> Self { + Self { + index_ligne, + erreur, + } + } +} + + +impl fmt::Display for ErreurCompilation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//' + write!(f, "Erreur ligne {} : {}", self.index_ligne + 1, self.erreur) + } +} + pub enum ErreurPendragon { CommandeInconnue(String), ManqueArgument, @@ -11,7 +32,7 @@ pub enum ErreurPendragon { MauvaisArgument(String), VariableInconnue(String), MauvaisType(String, String, String), - ManquePoint, + ManquePonctuation, Lecture(String), CalculBooleen(String), CalculEntier(String), @@ -29,7 +50,7 @@ impl fmt::Display for ErreurPendragon { 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 {} est du mauvais type ({}), attendais {}.", nom, type_variable, type_attendu), - Self::ManquePoint => write!(f, "Il manque un point."), + Self::ManquePonctuation => write!(f, "Il manque la ponctuation de la phrase."), 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), diff --git a/src/pendragon/mod.rs b/src/pendragon/mod.rs index 1879223..5c92835 100644 --- a/src/pendragon/mod.rs +++ b/src/pendragon/mod.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::time::Instant; pub mod nombre; pub mod texte; @@ -20,38 +19,42 @@ impl Pendragon { } } - pub fn compile(&mut self, contenu: String) -> Result<(), ErreurPendragon> { - println!(); - let debut = Instant::now(); - let contenu_propre = contenu.replace("\n", " "); - let mut texte: Vec<&str> = contenu_propre.split('.').collect(); - let reste = texte.pop(); - if reste != Some("") { - eprintln!("Erreur Compilation, phrase {} : Il manque un point.", texte.len() + 1); - return Err(ErreurPendragon::ManquePoint) - } - for (index_phrase, phrase) in texte.iter().enumerate() { - let phrase = phrase.trim(); - match self.compile_phrase(phrase) { - Ok(commande) => {self.programme.ajoute_commande(commande)}, - Err(raison) => { - eprintln!("Erreur phrase {} : {}", index_phrase + 1, raison); - return Err(raison) + pub fn compile(&mut self, contenu: String) -> Result<(), ErreurCompilation> { + let texte: Vec<&str> = contenu.split('\n').collect(); + for (index_ligne, ligne) in texte.iter().enumerate() { + let ligne = ligne.trim(); + let phrases: Vec<&str> = ligne.split_inclusive(|c| c == ',' || c == '.').collect(); + let Some(derniere_phrase) = phrases.last() else { + continue + }; + if !derniere_phrase.ends_with('.') && !derniere_phrase.ends_with(',') { + return Err(ErreurCompilation::nouvelle(index_ligne, ErreurPendragon::ManquePonctuation)) + } + for phrase in phrases { + if phrase.ends_with(".") { + if phrase.starts_with("Nota Bene :") { + continue + } + match self.compile_commande(&phrase[..phrase.len() - 1]) { + Ok(commande) => self.programme.ajoute_commande(commande), + Err(raison) => return Err(ErreurCompilation::nouvelle(index_ligne, raison)), + } + continue; } + println!("todo : {}", phrase); } } - println!("# Compilation Ok. ({:.2?})\n", debut.elapsed()); Ok(()) } - fn compile_phrase(&mut self, phrase: &str) -> Result { + fn compile_commande(&mut self, phrase: &str) -> Result { let phrase = phrase.trim(); let parties: Vec<&str> = phrase.splitn(2, ' ').collect(); if parties.len() == 1 { return Err(ErreurPendragon::ManqueArgument) } if parties[1].contains("Définis") || parties[1].contains("Modifie") || parties[1].contains("Affiche") || parties[1].contains("Demande") { - return Err(ErreurPendragon::ManquePoint) + return Err(ErreurPendragon::ManquePonctuation) } match parties[0] { "Définis" => self.definis(parties[1]), diff --git a/src/pendragon/nombre.rs b/src/pendragon/nombre.rs index 6a78c55..6f0225e 100644 --- a/src/pendragon/nombre.rs +++ b/src/pendragon/nombre.rs @@ -15,6 +15,7 @@ impl Pendragon { let elements_texte: Vec<&str> = texte.split(" ").collect(); let mut expression: Vec = Vec::new(); let mut pile_operateurs: Vec = Vec::new(); + let mut precede_par_operation: bool = true; for element in elements_texte { match element { @@ -58,24 +59,43 @@ impl Pendragon { } pile_operateurs.push(Operateur::Divise); } - "ouvre-la-parenthese" => pile_operateurs.push(Operateur::ParentheseEntier), + "ouvre-la-parenthese" => { + if !precede_par_operation { + return Err(ErreurPendragon::CalculEntier("il manque un opérateur avant l'ouverture de parenthèse".into())) + } + pile_operateurs.push(Operateur::ParentheseEntier); + continue + } "ferme-la-parenthese" => { + if precede_par_operation { + return Err(ErreurPendragon::CalculEntier("il manque un nombre avant la fermeture de parenthèse".into())) + } while let Some(operateur) = pile_operateurs.pop() { if operateur == Operateur::ParentheseEntier { break; } expression.push(Element::Operateur(operateur)); } + continue } autre => { + if !precede_par_operation { + return Err(ErreurPendragon::CalculEntier(format!("il manque un opérateur avant le nombre '{}'", autre))) + } + precede_par_operation = false; 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)?); } + continue; } } + if precede_par_operation { + return Err(ErreurPendragon::CalculEntier(format!("il manque un nombre avant l'opérateur '{}'", element))) + } + precede_par_operation = true; } while let Some(operateur) = pile_operateurs.pop() { @@ -124,6 +144,9 @@ pub fn calcule_nombre(expression: Vec, variables: &HashMap { + if nombre_b < nombre_a { + return Err(ErreurPendragon::CalculEntier(format!("a essayé de soustraire {} à {}", nombre_a, nombre_b))) + } pile.push(nombre_b - nombre_a); } Operateur::Fois => { diff --git a/src/pendragon/structure.rs b/src/pendragon/structure.rs index ff9af12..e909280 100644 --- a/src/pendragon/structure.rs +++ b/src/pendragon/structure.rs @@ -1,6 +1,5 @@ use std::io; use std::collections::HashMap; -use std::time::Instant; use super::*; @@ -54,8 +53,6 @@ impl Programme { } pub fn execute(&self) -> Result<(), ErreurPendragon> { - let debut = Instant::now(); - println!("# Execution...\n"); let mut variables_globales: HashMap = HashMap::new(); for commande in &self.commandes { match commande { @@ -79,7 +76,6 @@ impl Programme { } } } - println!("\n# Exécution Ok. ({:.2?})", debut.elapsed()); Ok(()) } } diff --git a/src/pendragon/texte.rs b/src/pendragon/texte.rs index adaa218..347340a 100644 --- a/src/pendragon/texte.rs +++ b/src/pendragon/texte.rs @@ -4,7 +4,7 @@ impl Pendragon { pub fn elements_texte(&self, arguments: &str) -> Result, ErreurPendragon> { let mut expression: Vec = Vec::new(); - for argument in arguments.split(',').map(|arg| arg.trim()) { + for argument in arguments.split("puis").map(|arg| arg.trim()) { if expression.len() > 0 { expression.push(Element::Operateur(Operateur::Virgule)); } @@ -93,7 +93,7 @@ mod test { let a = 2345678; let b = 987654; - let possible_expression = pendragon.elements_texte(&format!("\"hello\", {} fois {}, \"there\", vrai ou faux", + let possible_expression = pendragon.elements_texte(&format!("\"hello\" puis {} fois {} puis \"there\" puis vrai ou faux", nombre::nombre_comme_texte(a), nombre::nombre_comme_texte(b))); match possible_expression { diff --git a/test.dr b/test.dr index 82e351e..3a2d0da 100644 --- a/test.dr +++ b/test.dr @@ -1,8 +1,10 @@ -Affiche soixante-dix. -Affiche soixante-et-onze. -<<<<<<< HEAD -Affiche vrai et ouvre la parenthèse six plus un est supérieur à ouvre la parenthèse deux fois deux ferme la parenthèse ferme la parenthèse. -======= -Affiche vrai et ouvre la parenthèse six plus un est supérieur à ouvre la parenthèse deux fois deux ferme la parenthèse ferme la parenthèse. +Définis A comme entier. +Définis B comme entier. +Définis C comme entier. +Nota Bene : A est la variable pour un polynôme. ->>>>>>> main +Modifie A avec dix-sept. +Demande C. +Modifie B avec trois fois A fois A plus deux fois A plus C. + +Affiche "Résultat : " puis B. \ No newline at end of file