diff --git a/pendragon.project b/pendragon.project index 6c2eb41..d40cd1c 100644 --- a/pendragon.project +++ b/pendragon.project @@ -1 +1 @@ -{"categories":[{"name":"todo","content":[{"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":"test multiple space in texte","description":"// Hello there","id":3},{"name":"test puis in texte","description":"// Hello there","id":2},{"name":"enchainement puis","description":"// Hello there","id":5},{"name":"guillemet mal ferme","description":"// Hello there","id":4},{"name":"display element","description":"for better print","id":6},{"name":"puis à la ligne, alinéa","description":"// Hello there","id":1},{"name":"teste double tiret","description":"// Hello there","id":2},{"name":"teste puis seul","description":"tout seul, seul devant, seul fin","id":3},{"name":"erreur calcul bool/nombre","description":"affiche element precedent lorsque mauvais enchainement","id":1},{"name":"multiple compilation error","description":"// Hello there","id":1},{"name":"tests mod","description":"// Hello there","id":3}]},{"name":"bug","content":[]},{"name":"to test","content":[{"name":"test variable","description":"// Hello there","id":2}]},{"name":"bonus","content":[{"name":"stop cheating with \"-\"","description":"// Hello there","id":5},{"name":"affiche ligne et position erreur","description":"// Hello there","id":1},{"name":"pour numero de ligne execution","description":"sauvegarde numero de ligne dans la commande\n\ncommande.ligne(12)","id":3},{"name":"standardizer erreur","description":"regarder les texte répétés","id":1}]},{"name":"+","content":[]}]} \ No newline at end of file +{"categories":[{"name":"todo","content":[{"name":"verifie si bloc pas vide","description":"// Hello there","id":2},{"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":"test multiple space in texte","description":"// Hello there","id":3},{"name":"test puis in texte","description":"// Hello there","id":2},{"name":"enchainement puis","description":"// Hello there","id":5},{"name":"guillemet mal ferme","description":"// Hello there","id":4},{"name":"display element","description":"for better print","id":6},{"name":"puis à la ligne, alinéa","description":"// Hello there","id":1},{"name":"teste double tiret","description":"// Hello there","id":2},{"name":"teste puis seul","description":"tout seul, seul devant, seul fin","id":3},{"name":"erreur calcul bool/nombre","description":"affiche element precedent lorsque mauvais enchainement","id":1},{"name":"multiple compilation error","description":"// Hello there","id":1},{"name":"tests mod","description":"// Hello there","id":3},{"name":"if","description":"implémente if avec des guillemets de délimitation","id":1}]},{"name":"bug","content":[]},{"name":"to test","content":[{"name":"test variable","description":"// Hello there","id":2},{"name":"teste if","description":"// Hello there","id":3}]},{"name":"bonus","content":[{"name":"stop cheating with \"-\"","description":"// Hello there","id":5},{"name":"affiche ligne et position erreur","description":"// Hello there","id":1},{"name":"pour numero de ligne execution","description":"sauvegarde numero de ligne dans la commande\n\ncommande.ligne(12)","id":3},{"name":"standardizer erreur","description":"regarder les texte répétés","id":1}]},{"name":"+","content":[]}]} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 4820249..9e9128b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,7 +37,7 @@ fn main() { debug::message_compilation_ok(debut.elapsed()); if debug_mode { - println!("{}\n", pendragon.programme); + println!("\n{}\n", pendragon.programme); } diff --git a/src/pendragon/booleen.rs b/src/pendragon/booleen.rs index 528c516..3ac1ecd 100644 --- a/src/pendragon/booleen.rs +++ b/src/pendragon/booleen.rs @@ -170,17 +170,24 @@ impl Pendragon { } pub fn ajoute_comparaison_membre(&self, comparaison: &mut Comparaison, texte: &str) -> Result<(), ErreurPendragon> { - let membre = if let Ok(elements_nombre) = self.elements_nombre(texte) { - elements_nombre - } else if let Ok(elements_booleen) = self.elements_booleen(texte) { - elements_booleen - } else if let Ok(elements_texte) = self.elements_texte(texte) { - elements_texte - } else { - return Err(ErreurPendragon::MauvaisArgument(texte.to_string())); - }; + let mut membre: Vec = vec![]; + match self.elements_nombre(texte) { + Ok(elements_nombre) => membre = elements_nombre, + Err(raison) => if let ErreurPendragon::OrdreCalculEntier(_,_,_) = raison {return Err(raison)}, + } + if membre.is_empty() { + match self.elements_booleen(texte) { + Ok(elements_booleen) => membre = elements_booleen, + Err(raison) => if let ErreurPendragon::OrdreCalculBooleen(_,_,_) = raison {return Err(raison)}, + } + } + if membre.is_empty() { + if let Ok(elements_texte) = self.elements_texte(texte) { + membre = elements_texte; + } + } let Some(element) = membre.first() else { - return Err(ErreurPendragon::ComparaisonInvalide("il n'y a pas de d'élément dans le membre ajouté".into())) + return Err(ErreurPendragon::MauvaisArgument(texte.to_string())) }; if comparaison.type_comparaison.is_none() { comparaison.membre_a = membre; diff --git a/src/pendragon/debug.rs b/src/pendragon/debug.rs index e42d0e9..0af12cd 100644 --- a/src/pendragon/debug.rs +++ b/src/pendragon/debug.rs @@ -64,8 +64,10 @@ impl fmt::Display for ErreurCompilation { #[derive(PartialEq, Debug, Clone)] pub enum ErreurPendragon { CommandeInconnue(String), + BlocInconnu(String), ManqueArgument, MauvaisArgument(String), + MauvaiseIndentation(String), ManquePonctuation, NombreInvalide(String), @@ -89,8 +91,10 @@ 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::BlocInconnu(bloc) => write!(f, "Le bloc \"{}\" est inconnu.", bloc), Self::ManqueArgument => write!(f, "Il manque un argument."), Self::MauvaisArgument(message) => write!(f, "La commande a reçu un mauvais argument, {}.", message), + Self::MauvaiseIndentation(message) => write!(f, "L'indentation est mauvaise, {}.", message), Self::ManquePonctuation => write!(f, "Il manque la ponctuation de la phrase."), Self::NombreInvalide(nombre) => write!(f, "Le nombre \"{}\" est mal orthographié.", nombre), diff --git a/src/pendragon/mod.rs b/src/pendragon/mod.rs index e5c0ecc..48afec5 100644 --- a/src/pendragon/mod.rs +++ b/src/pendragon/mod.rs @@ -22,7 +22,11 @@ impl Pendragon { pub fn compile(&mut self, contenu: String) -> Result<(), Vec> { let texte: Vec<&str> = contenu.split('\n').collect(); let mut erreurs: Vec = vec![]; + let mut indentation_niveau: usize = 0; + let mut pile_bloc: Vec = vec![]; + for (index_ligne, ligne) in texte.iter().enumerate() { + let indentation_ligne = ligne.chars().take_while(|&c| c == '\t').count(); let ligne = ligne.trim(); let phrases: Vec<&str> = ligne.split_inclusive(|c| c == ',' || c == '.').collect(); let Some(derniere_phrase) = phrases.last() else { @@ -31,18 +35,47 @@ impl Pendragon { if !derniere_phrase.ends_with('.') && !derniere_phrase.ends_with(',') { erreurs.push(ErreurCompilation::nouvelle(index_ligne, ligne.into(), ErreurPendragon::ManquePonctuation)) } + while indentation_ligne < indentation_niveau { + let Some(bloc_actuel) = pile_bloc.pop() else { + erreurs.push(ErreurCompilation::nouvelle(index_ligne, ligne.into(), ErreurPendragon::MauvaiseIndentation(format!("croyais être à {} niveau", indentation_niveau)),)); + indentation_niveau = 0; + continue; + }; + if let Some(bloc_precedent) = pile_bloc.last_mut() { + bloc_precedent.ajoute_bloc(bloc_actuel); + } else { + self.programme.ajoute_bloc(bloc_actuel); + } + indentation_niveau -= 1; + } + for phrase in phrases { if phrase.ends_with(".") { if phrase.replace(" ", "").starts_with("NotaBene:") { continue } match self.compile_commande(&phrase[..phrase.len() - 1]) { - Ok(commande) => self.programme.ajoute_commande(commande), + Ok(commande) => { + if let Some(bloc_actuel) = pile_bloc.last_mut() { + bloc_actuel.ajoute_commande(commande); + } else { + self.programme.ajoute_commande(commande); + } + } Err(raison) => erreurs.push(ErreurCompilation::nouvelle(index_ligne, ligne.into(), raison)), } continue; } - println!("todo : {}", phrase); + match self.compile_bloc(&phrase[..phrase.len() - 1]) { + Ok(bloc) => { + pile_bloc.push(bloc); + } + Err(raison) => { + erreurs.push(ErreurCompilation::nouvelle(index_ligne, ligne.into(), raison)); + pile_bloc.push(Bloc::nouveau(vec![Element::Booleen(false)])); + } + } + indentation_niveau += 1; } } if erreurs.len() > 0 { @@ -57,7 +90,7 @@ impl Pendragon { 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") { + if contient_mot_cle(parties[1]) { return Err(ErreurPendragon::ManquePonctuation) } match parties[0] { @@ -68,6 +101,22 @@ impl Pendragon { autre => Err(ErreurPendragon::CommandeInconnue(autre.into())), } } + + fn compile_bloc(&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 contient_mot_cle(parties[1]) { + return Err(ErreurPendragon::ManquePonctuation) + } + + match parties[0] { + "Si" => Ok(Bloc::nouveau(self.elements_booleen(parties[1])?)), + autre => Err(ErreurPendragon::BlocInconnu(autre.into())), + } + } fn affiche(&self, arguments: &str) -> Result { Ok(Commande::Affiche(self.elements_texte(arguments)?)) @@ -103,6 +152,14 @@ impl Pendragon { } } +fn contient_mot_cle(texte: &str) -> bool { + texte.contains("Définis") || + texte.contains("Modifie") || + texte.contains("Affiche") || + texte.contains("Demande") || + texte.contains("Si") +} + fn nom_de_variable(arguments: &str, separateur: &str) -> Result<(String, String), ErreurPendragon> { let parties = if separateur == "" { vec![arguments, ""] diff --git a/src/pendragon/structure.rs b/src/pendragon/structure.rs index ea5ae8e..7172498 100644 --- a/src/pendragon/structure.rs +++ b/src/pendragon/structure.rs @@ -20,6 +20,10 @@ impl Programme { self.contenu.push(Phrase::Commande(commande)); } + pub fn ajoute_bloc(&mut self, bloc: Bloc) { + self.contenu.push(Phrase::Bloc(bloc)); + } + 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))) @@ -55,11 +59,10 @@ impl Programme { pub fn execute(&self) -> Result<(), ErreurPendragon> { let mut variables_globales: HashMap = HashMap::new(); for phrase in &self.contenu { - let Phrase::Commande(commande) = phrase else { - println!("doit executer bloc"); - continue; - }; - commande.execute(&mut variables_globales)?; + match phrase { + Phrase::Commande(commande) => commande.execute(&mut variables_globales)?, + Phrase::Bloc(bloc) => bloc.execute(&mut variables_globales)?, + } } Ok(()) } @@ -70,6 +73,36 @@ pub struct Bloc { contenu: Vec, } +impl Bloc { + pub fn nouveau(condition: Vec) -> Self { + Self { + condition, + contenu: vec![], + } + } + + pub fn ajoute_commande(&mut self, commande: Commande) { + self.contenu.push(Phrase::Commande(commande)); + } + + pub fn ajoute_bloc(&mut self, bloc: Bloc) { + self.contenu.push(Phrase::Bloc(bloc)); + } + + pub fn execute(&self, variables: &mut HashMap) -> Result<(), ErreurPendragon> { + if !booleen::calcule_booleen(self.condition.clone(), variables)? { + return Ok(()); + } + for phrase in &self.contenu { + match phrase { + Phrase::Commande(commande) => commande.execute(variables)?, + Phrase::Bloc(bloc) => bloc.execute(variables)?, + } + } + Ok(()) + } +} + pub enum Phrase { Bloc(Bloc), Commande(Commande), diff --git a/test.dr b/test.dr index ed413a1..1344c18 100644 --- a/test.dr +++ b/test.dr @@ -3,17 +3,17 @@ Définis B comme entier. Définis C comme entier. Nota Bene : A est la variable pour un polynôme. -Modifie A avec dix-sept plus trois. +Demande A. Modifie C avec six-cent-soixante-douze. Modifie B avec trois fois A fois ouvre la parenthèse trois fois A plus C ferme la parenthèse. Nota Bene : 3*A*(3*A+C). Affiche "Résultat : " puis B. -Si A supérieur ou égal à deux trois, +Si A est inférieur ou égal à trois, + Affiche "A<=3". + Si B est inférieur ou égal à trois, + Affiche "B<=3". + Affiche "fin B". -Définis Bool comme booléen. -Modifie Bool avec vrai. -Affiche vrai et faux. - -Affiche alinéa puis trois plus un puis retour à la ligne puis "test". \ No newline at end of file +Affiche "test". \ No newline at end of file