Compare commits
No commits in common. "537b5157e6b4095791e7e69f0246ba0ae7729ed5" and "90322f7bcf571823c9f5e6ab074c3766f918d429" have entirely different histories.
537b5157e6
...
90322f7bcf
32
README.md
32
README.md
|
@ -1,32 +0,0 @@
|
||||||
# Pendragon
|
|
||||||
|
|
||||||
Un language de programmation avec la syntaxe d'un texte français.
|
|
||||||
|
|
||||||
## Pour l'instant
|
|
||||||
- La partie pendragon/ transforme le fichier '.dr' en AST (arbre de syntaxe)
|
|
||||||
- La parte sophie/ interprète l'AST
|
|
||||||
## Objectif
|
|
||||||
- La partie hurle/ pour convertir l'AST en IR de LLVM
|
|
||||||
- Compilation avec LLVM
|
|
||||||
## Exemple
|
|
||||||
Voici un exemple de code :
|
|
||||||
|
|
||||||
```
|
|
||||||
Définis A comme entier. Définis B comme entier.
|
|
||||||
Modifie B avec un.
|
|
||||||
|
|
||||||
Définis N comme entier.
|
|
||||||
Modifie N avec trente.
|
|
||||||
|
|
||||||
Tant que N est supérieur à zéro,
|
|
||||||
Modifie N avec N moins un.
|
|
||||||
|
|
||||||
Affiche A.
|
|
||||||
Affiche B.
|
|
||||||
Modifie A avec A plus B.
|
|
||||||
Modifie B avec A plus B.
|
|
||||||
|
|
||||||
Affiche "Fin".
|
|
||||||
|
|
||||||
Nota Bene : Ceci est un programme qui affiche deux fois N nombres de la suite de Fibonacci.
|
|
||||||
```
|
|
|
@ -1 +1 @@
|
||||||
{"categories":[{"name":"todo","content":[{"name":"compilation","description":"// Hello there","id":3},{"name":"warning bloc vide","description":"// Hello there","id":2},{"name":"warning variable inutilisée","description":"// Hello there","id":1},{"name":"scope variable","description":"// Hello there","id":6},{"name":"else","description":"// Hello there","id":7},{"name":"break","description":"// Hello there","id":8},{"name":"continue","description":"// Hello there","id":9}]},{"name":"done","content":[]},{"name":"bug","content":[{"name":"erreur de comparaison sans \"est\"","description":"// Hello there","id":1}]},{"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":"+","content":[]}]}
|
{"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":"bug","content":[]},{"name":"to test","content":[{"name":"tests mod","description":"// Hello there","id":3},{"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":[]}]}
|
|
@ -1,239 +0,0 @@
|
||||||
use std::fmt;
|
|
||||||
use std::time::Duration;
|
|
||||||
use crate::pendragon::structure::*;
|
|
||||||
use crate::sophie;
|
|
||||||
|
|
||||||
pub const TEXTE_ROUGE: &str = "\x1b[31m";
|
|
||||||
pub const TEXTE_VERT: &str = "\x1b[32m";
|
|
||||||
//pub const TEXTE_JAUNE: &str = "\x1b[33m";
|
|
||||||
pub const TEXTE_BLEU: &str = "\x1b[34m";
|
|
||||||
pub const TEXTE_GRIS: &str = "\x1b[37m";
|
|
||||||
pub const TEXTE_NORMAL: &str = "\x1b[0m";
|
|
||||||
|
|
||||||
pub fn message_compilation(chemin_de_fichier: &str) {
|
|
||||||
println!("\n- Compilation de {}'{}'{}...", TEXTE_VERT, chemin_de_fichier, TEXTE_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn message_compilation_echec() {
|
|
||||||
eprintln!("\n{}x Échec de la compilation.{}",TEXTE_ROUGE, TEXTE_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn message_compilation_ok(temps: Duration) {
|
|
||||||
println!("{}✓ Compilation Ok.{} ({:.2?}){}", TEXTE_VERT, TEXTE_GRIS, temps, TEXTE_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn message_execution(chemin_de_fichier: &str) {
|
|
||||||
println!("- Exécution de {}'{}'{}...\n", TEXTE_VERT, chemin_de_fichier, TEXTE_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn message_execution_echec() {
|
|
||||||
eprintln!("\n{}x Échec de l'exécution.{}",TEXTE_ROUGE, TEXTE_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn message_execution_ok(temps: Duration) {
|
|
||||||
println!("\n{}✓ Exécution Ok.{} ({:.2?}){}", TEXTE_VERT, TEXTE_GRIS, temps, TEXTE_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ErreurCompilation {
|
|
||||||
index_ligne: usize,
|
|
||||||
ligne: String,
|
|
||||||
erreur: ErreurPendragon,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ErreurCompilation {
|
|
||||||
pub fn nouvelle(index_ligne: usize, ligne: String, erreur: ErreurPendragon) -> Self {
|
|
||||||
Self {
|
|
||||||
index_ligne,
|
|
||||||
ligne,
|
|
||||||
erreur,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn raison(&self) -> ErreurPendragon {
|
|
||||||
self.erreur.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl fmt::Display for ErreurCompilation {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
|
||||||
write!(f, "{}Erreur :{} {}\n{}ligne {} : {}{}", TEXTE_ROUGE, TEXTE_NORMAL, self.erreur, TEXTE_GRIS, self.index_ligne + 1, self.ligne, TEXTE_NORMAL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
|
||||||
pub enum ErreurPendragon {
|
|
||||||
CommandeInconnue(String),
|
|
||||||
BlocInconnu(String),
|
|
||||||
ManqueArgument,
|
|
||||||
MauvaisArgument(String),
|
|
||||||
MauvaiseIndentation(String),
|
|
||||||
ManquePonctuation,
|
|
||||||
|
|
||||||
NombreInvalide(String),
|
|
||||||
CalculEntier(String),
|
|
||||||
OrdreCalculEntier(String, String, String),
|
|
||||||
|
|
||||||
TexteInvalide(String),
|
|
||||||
|
|
||||||
BooleenInvalide(String),
|
|
||||||
ComparaisonInvalide(String),
|
|
||||||
CalculBooleen(String),
|
|
||||||
OrdreCalculBooleen(String, String, String),
|
|
||||||
|
|
||||||
VariableInconnue(String),
|
|
||||||
MauvaisType(String, String, String),
|
|
||||||
|
|
||||||
Lecture(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::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),
|
|
||||||
Self::CalculEntier(raison) => write!(f, "Calcul entier échoué, {}.", raison),
|
|
||||||
Self::OrdreCalculEntier(manque, precedent, suivant) => write!(f, "Calcul entier échoué, il manque un {} entre '{}' et '{}'.", manque, precedent, suivant),
|
|
||||||
|
|
||||||
Self::TexteInvalide(raison) => write!(f, "Le texte est invalide, {}.", raison),
|
|
||||||
|
|
||||||
Self::BooleenInvalide(booleen) => write!(f, "Le booleen \"{}\" est invalide.", booleen),
|
|
||||||
Self::CalculBooleen(raison) => write!(f, "Calcul booleen échoué, {}.", raison),
|
|
||||||
Self::ComparaisonInvalide(raison) => write!(f, "La comparaison est invalide, {}.", raison),
|
|
||||||
Self::OrdreCalculBooleen(manque, precedent, suivant) => write!(f, "Calcul boolen échoué, il manque un {} entre '{}' et '{}'.", manque, precedent, suivant),
|
|
||||||
|
|
||||||
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::Lecture(raison) => write!(f, "Lecture d'entrées utilisateur impossible : {}.", raison),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Commande {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
|
||||||
match self {
|
|
||||||
Self::Definis(nom, type_element) => write!(f, "{}{}{}:{}", TEXTE_VERT, nom, TEXTE_NORMAL, type_element.nom()),
|
|
||||||
Self::Demande(nom) => write!(f, "{}{}{}?", TEXTE_VERT, nom, TEXTE_NORMAL),
|
|
||||||
Self::Modifie(nom, expression) => write!(f,"{}{}{}={}[{}{}{}]{}", TEXTE_VERT, nom, TEXTE_NORMAL, TEXTE_ROUGE, TEXTE_NORMAL, liste_element(&expression), TEXTE_ROUGE, TEXTE_NORMAL),
|
|
||||||
Self::Affiche(expression) => write!(f, "#{}[{}{}{}]{}", TEXTE_ROUGE, TEXTE_NORMAL, liste_element(&expression), TEXTE_ROUGE, TEXTE_NORMAL),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Element {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
|
||||||
match self {
|
|
||||||
Self::Entier(nombre) => write!(f, "{}", sophie::nombre::nombre_comme_texte(*nombre)),
|
|
||||||
Self::Texte(texte) => write!(f, "\"{}\"", texte),
|
|
||||||
Self::Booleen(booleen) => write!(f, "{}", sophie::booleen::booleen_comme_texte(*booleen)),
|
|
||||||
Self::Variable(nom, type_variable) => write!(f, "{}{}{}:{}", TEXTE_VERT, nom, TEXTE_NORMAL, type_variable.nom()),
|
|
||||||
Self::Operateur(operateur) => write!(f, "{}", operateur),
|
|
||||||
Self::Comparaison(comparaison) => write!(f, "{}", comparaison),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Comparaison {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
|
||||||
let mut texte_membre_a: String = String::new();
|
|
||||||
for element in &self.membre_a {
|
|
||||||
texte_membre_a += &format!("{} ", element);
|
|
||||||
}
|
|
||||||
let mut texte_membre_b: String = String::new();
|
|
||||||
for element in &self.membre_b {
|
|
||||||
texte_membre_b += &format!(" {}", element);
|
|
||||||
}
|
|
||||||
let comparaison = if let Some(type_comparaison) = &self.type_comparaison {
|
|
||||||
format!("{}", type_comparaison)
|
|
||||||
} else {
|
|
||||||
"?".to_string()
|
|
||||||
};
|
|
||||||
write!(f, "({}{}{})",
|
|
||||||
texte_membre_a,
|
|
||||||
comparaison,
|
|
||||||
texte_membre_b,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TypeComparaison {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
|
||||||
match self {
|
|
||||||
Self::Egal => write!(f, "=="),
|
|
||||||
Self::Different => write!(f, "!="),
|
|
||||||
Self::SuperieurEgal => write!(f, ">="),
|
|
||||||
Self::InferieurEgal => write!(f, "<="),
|
|
||||||
Self::Superieur => write!(f, ">"),
|
|
||||||
Self::Inferieur => write!(f, "<"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Operateur {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
|
||||||
match self {
|
|
||||||
Self::Ou => write!(f, "ou"),
|
|
||||||
Self::Et => write!(f, "et"),
|
|
||||||
Self::Non => write!(f, "non"),
|
|
||||||
Self::ParentheseBooleen => write!(f, "["),
|
|
||||||
Self::Puis => write!(f, "~"),
|
|
||||||
Self::Plus => write!(f, "+"),
|
|
||||||
Self::Moins => write!(f, "-"),
|
|
||||||
Self::Fois => write!(f, "x"),
|
|
||||||
Self::Divise => write!(f, "/"),
|
|
||||||
Self::ParentheseEntier => write!(f, "("),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Programme {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
|
||||||
let mut texte: String = format!("{}variables : {:?}{}\n\n", TEXTE_GRIS, self.variables, TEXTE_NORMAL);
|
|
||||||
for phrase in &self.contenu {
|
|
||||||
texte += &format!("{}\n", phrase);
|
|
||||||
}
|
|
||||||
write!(f, "{}", texte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Phrase {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
|
||||||
match self {
|
|
||||||
Self::Commande(commande) => write!(f, "{}", commande),
|
|
||||||
Self::Bloc(bloc) => write!(f, "{}", bloc),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Bloc {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
|
||||||
let mut texte: String = format!("|{}| : {}[{}", liste_element(&self.condition), TEXTE_BLEU, TEXTE_NORMAL);
|
|
||||||
for (index, phrase) in self.contenu.iter().enumerate() {
|
|
||||||
texte += &format!("{}", phrase);
|
|
||||||
if index < self.contenu.len() - 1 {
|
|
||||||
texte += &format!("{},{} ", TEXTE_GRIS, TEXTE_NORMAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "{}{}]{}", texte, TEXTE_BLEU, TEXTE_NORMAL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn liste_element(expression: &Vec<Element>) -> String {
|
|
||||||
let mut texte = String::new();
|
|
||||||
for (index, element) in expression.iter().enumerate() {
|
|
||||||
texte += &format!("{}", element);
|
|
||||||
if index < expression.len() - 1 {
|
|
||||||
texte += &format!("{},{} ", TEXTE_GRIS, TEXTE_NORMAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
texte
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
pub mod display;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test;
|
|
||||||
|
|
|
@ -1,318 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use crate::sophie;
|
|
||||||
use crate::pendragon;
|
|
||||||
use crate::display::*;
|
|
||||||
use crate::structure::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn calcul_texte() {
|
|
||||||
let pendragon = pendragon::Pendragon::nouveau();
|
|
||||||
let a = 2345678;
|
|
||||||
let b = 987654;
|
|
||||||
|
|
||||||
let possible_expression = pendragon.elements_texte(&format!("\"hello\" puis {} fois {} puis \"there\" puis vrai ou faux puis trois puis deux puis alinéa puis retour à la ligne",
|
|
||||||
sophie::nombre::nombre_comme_texte(a),
|
|
||||||
sophie::nombre::nombre_comme_texte(b)));
|
|
||||||
match possible_expression {
|
|
||||||
Ok(expression) => {
|
|
||||||
match sophie::texte::calcule_texte(expression, &HashMap::new()) {
|
|
||||||
Ok(texte) => {
|
|
||||||
let vrai_texte = format!("hello{}therevraitroisdeux\t\n", sophie::nombre::nombre_comme_texte(a*b));
|
|
||||||
assert_eq!(texte, vrai_texte, "Calcul d'expression (texte) donne un mauvais résultat : {}", texte);
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Calcul d'expression (texte) échoué, avec l'erreur : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Détermination d'expression (texte) échouée : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn conversion_texte() {
|
|
||||||
let pendragon = pendragon::Pendragon::nouveau();
|
|
||||||
let texte = "\"hello aaaa puis AERTY et ou fois six\"";
|
|
||||||
match pendragon.elements_texte(texte) {
|
|
||||||
Ok(expression) => {
|
|
||||||
if expression.len() != 2 {
|
|
||||||
panic!("L'expression (texte) devrait contenir deux éléments (texte et puis), contient : {:?}", expression);
|
|
||||||
}
|
|
||||||
assert_eq!(expression[0], Element::Texte(texte[1..texte.len()-1].into()), "Calcul d'expression (texte) donne un mauvais résultat : {}", texte);
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Conversion échouée (texte) : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn erreur_conversion_texte() {
|
|
||||||
let pendragon = pendragon::Pendragon::nouveau();
|
|
||||||
let textes = vec![
|
|
||||||
"trois puis puis un",
|
|
||||||
"\" test",
|
|
||||||
"puis",
|
|
||||||
"un puis",
|
|
||||||
"puis un",
|
|
||||||
];
|
|
||||||
for texte in textes {
|
|
||||||
let Err(raison) = pendragon.elements_texte(texte) else {
|
|
||||||
panic!("Ne devrait pas réussir à convertir le texte '{}'", texte);
|
|
||||||
};
|
|
||||||
let ErreurPendragon::TexteInvalide(_) = raison else {
|
|
||||||
panic!("Erreur imprévue pour convertir le texte '{}' : {}", texte, raison);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn conversion_booleen_texte() {
|
|
||||||
for b in [true, false].iter() {
|
|
||||||
let texte = sophie::booleen::booleen_comme_texte(*b); // Convert number to text
|
|
||||||
match pendragon::booleen::texte_comme_booleen(&texte) { // Convert text back to number
|
|
||||||
Ok(booleen) => {
|
|
||||||
assert_eq!(Element::Booleen(*b), booleen, "Booleen inexact : {}, texte : {}", b, texte);
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Conversion échouée pour : {}, avec l'erreur : {}", b, raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn calcul_booleen() {
|
|
||||||
let pendragon = pendragon::Pendragon::nouveau();
|
|
||||||
let mut configurations = Vec::new();
|
|
||||||
for b1 in [true, false] {
|
|
||||||
for b2 in [true, false] {
|
|
||||||
for b3 in [true, false] {
|
|
||||||
for b4 in [true, false] {
|
|
||||||
for b5 in [true, false] {
|
|
||||||
configurations.push((b1, b2, b3, b4, b5));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for configuration in configurations {
|
|
||||||
let possible_expression = pendragon.elements_booleen(&format!("{} et non ouvre la parenthèse {} ou non {} ferme la parenthèse ou non {} et {}",
|
|
||||||
sophie::booleen::booleen_comme_texte(configuration.0),
|
|
||||||
sophie::booleen::booleen_comme_texte(configuration.1),
|
|
||||||
sophie::booleen::booleen_comme_texte(configuration.2),
|
|
||||||
sophie::booleen::booleen_comme_texte(configuration.3),
|
|
||||||
sophie::booleen::booleen_comme_texte(configuration.4)));
|
|
||||||
match possible_expression {
|
|
||||||
Ok(expression) => {
|
|
||||||
match sophie::booleen::calcule_booleen(expression, &HashMap::new()) {
|
|
||||||
Ok(booleen) => {
|
|
||||||
let resultat = configuration.0 && !(configuration.1 || !configuration.2) || !configuration.3 && configuration.4;
|
|
||||||
assert_eq!(booleen, resultat, "Calcul d'expression (booleen) donne un mauvais résultat : {}", booleen);
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Calcul d'expression (booleen) échoué, avec l'erreur : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Détermination d'expression (booleen) échouée : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn comparaison_booleen() {
|
|
||||||
let pendragon = pendragon::Pendragon::nouveau();
|
|
||||||
for (a, b) in [(1, 4), (2, 2), (3, 1), (0, 3)] {
|
|
||||||
let possible_expressions = vec![
|
|
||||||
pendragon.elements_booleen(&format!("non six plus {} est supérieur à deux fois {}", sophie::nombre::nombre_comme_texte(a), sophie::nombre::nombre_comme_texte(b))),
|
|
||||||
pendragon.elements_booleen(&format!("six plus {} est inférieur à deux fois {}", sophie::nombre::nombre_comme_texte(a), sophie::nombre::nombre_comme_texte(b))),
|
|
||||||
pendragon.elements_booleen(&format!("six plus {} est supérieur ou égal à deux fois {}", sophie::nombre::nombre_comme_texte(a), sophie::nombre::nombre_comme_texte(b))),
|
|
||||||
pendragon.elements_booleen(&format!("non six plus {} est inférieur ou égal à deux fois {}", sophie::nombre::nombre_comme_texte(a), sophie::nombre::nombre_comme_texte(b))),
|
|
||||||
pendragon.elements_booleen(&format!("non \"deux\" est égal à \"{}\"", sophie::nombre::nombre_comme_texte(a))),
|
|
||||||
pendragon.elements_booleen(&format!("\"trois\" est différent de \"{}\"", sophie::nombre::nombre_comme_texte(a))),
|
|
||||||
];
|
|
||||||
let bonne_reponses = vec![
|
|
||||||
!(6+a > 2*b),
|
|
||||||
(6+a < 2*b),
|
|
||||||
(6+a >= 2*b),
|
|
||||||
!(6+a <= 2*b),
|
|
||||||
!(a == 2),
|
|
||||||
(a != 3),
|
|
||||||
];
|
|
||||||
for index in 0..possible_expressions.len() {
|
|
||||||
match &possible_expressions[index] {
|
|
||||||
Ok(expression) => {
|
|
||||||
match sophie::booleen::calcule_booleen(expression.clone(), &HashMap::new()) {
|
|
||||||
Ok(booleen) => {
|
|
||||||
let reponse = bonne_reponses[index];
|
|
||||||
assert_eq!(booleen, reponse, "Calcul d'expression (booleen) n°{} ({},{}) donne un mauvais résultat : {}, attendais {}", index, a, b, booleen, reponse);
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Calcul d'expression (booleen) échoué, avec l'erreur : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Détermination d'expression (booleen) échouée : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn combinaison_booleen() {
|
|
||||||
let pendragon = pendragon::Pendragon::nouveau();
|
|
||||||
for a in 0..5 {
|
|
||||||
for b in 0..5 {
|
|
||||||
for c in 0..5 {
|
|
||||||
for d in 1..5 {
|
|
||||||
for e in 0..5 {
|
|
||||||
let possible_expression = pendragon.elements_booleen(&format!("non ouvre la parenthèse six plus {} ferme la parenthèse est supérieur à deux fois {} et ouvre la parenthèse {} divisé par deux est inférieur à ouvre la parenthèse {} moins un ferme la parenthèse ou non \"deux\" est égal à \"{}\" ferme la parenthèse",
|
|
||||||
sophie::nombre::nombre_comme_texte(a),
|
|
||||||
sophie::nombre::nombre_comme_texte(b),
|
|
||||||
sophie::nombre::nombre_comme_texte(c),
|
|
||||||
sophie::nombre::nombre_comme_texte(d),
|
|
||||||
sophie::nombre::nombre_comme_texte(e),
|
|
||||||
));
|
|
||||||
let bonne_reponse = !((6+a) > 2*b) && (c/2 < (d-1) || !(e == 2));
|
|
||||||
match possible_expression {
|
|
||||||
Ok(expression) => {
|
|
||||||
match sophie::booleen::calcule_booleen(expression.clone(), &HashMap::new()) {
|
|
||||||
Ok(booleen) => {
|
|
||||||
assert_eq!(booleen, bonne_reponse, "Calcul d'expression (booleen) ({},{},{},{},{}) donne un mauvais résultat : {}, attendais {}", a, b, c, d, e, booleen, bonne_reponse);
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Calcul d'expression (booleen) échoué, avec l'erreur : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Détermination d'expression (booleen) échouée : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn erreur_calcul_booleen() {
|
|
||||||
let pendragon = pendragon::Pendragon::nouveau();
|
|
||||||
let textes_invalide = vec![
|
|
||||||
"et faux",
|
|
||||||
"vrai et et faux",
|
|
||||||
"vrai ou ou faux",
|
|
||||||
"vrai et vrai faux",
|
|
||||||
"vrai et faux vrai",
|
|
||||||
"vrai et faux ouvre la parenthèse vrai ou faux ferme la parenthèse",
|
|
||||||
"vrai et ouvre la parenthèse et vrai ou faux ferme la parenthèse",
|
|
||||||
"vrai et ouvre la parenthèse vrai ou faux et ferme la parenthèse",
|
|
||||||
"vrai et ouvre la parenthèse vrai ou faux ferme la parenthèse vrai",
|
|
||||||
];
|
|
||||||
for texte in textes_invalide {
|
|
||||||
let Err(raison) = pendragon.elements_booleen(texte) else {
|
|
||||||
panic!("Devrait détecter une erreur pour '{}'", texte);
|
|
||||||
};
|
|
||||||
let ErreurPendragon::OrdreCalculBooleen(_,_,_) = raison else {
|
|
||||||
panic!("Devrait détecter une erreur de calcul booléen pour '{}', a déclenché : {}", texte, raison);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn conversion_nombres_texte() {
|
|
||||||
for i in [0, 1, 42, 70, 123, 999, 1031, 1_001_091, 72_036_854_775_807usize, 2345678*987654].iter() {
|
|
||||||
let texte = sophie::nombre::nombre_comme_texte(*i); // Convert number to text
|
|
||||||
if texte.contains("--") {
|
|
||||||
panic!("Il y a deux tirets pour {} : {}", i, texte);
|
|
||||||
}
|
|
||||||
match pendragon::nombre::texte_comme_nombre(&texte) { // Convert text back to number
|
|
||||||
Ok(nombre) => {
|
|
||||||
assert_eq!(Element::Entier(*i), nombre, "Nombre inexact : {}, texte : {}", i, texte);
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Conversion échouée pour : {}, avec l'erreur : {}", i, raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn calcul_nombre() {
|
|
||||||
let pendragon = pendragon::Pendragon::nouveau();
|
|
||||||
let a = 2345678;
|
|
||||||
let b = 987654;
|
|
||||||
let c = 34523456;
|
|
||||||
let d = 45678;
|
|
||||||
let e = 2;
|
|
||||||
let possible_expression = pendragon.elements_nombre(&format!("{} fois {} plus ouvre la parenthèse {} moins {} ferme la parenthèse divisé par {}",
|
|
||||||
sophie::nombre::nombre_comme_texte(a),
|
|
||||||
sophie::nombre::nombre_comme_texte(b),
|
|
||||||
sophie::nombre::nombre_comme_texte(c),
|
|
||||||
sophie::nombre::nombre_comme_texte(d),
|
|
||||||
sophie::nombre::nombre_comme_texte(e)));
|
|
||||||
match possible_expression {
|
|
||||||
Ok(expression) => {
|
|
||||||
match sophie::nombre::calcule_nombre(expression, &HashMap::new()) {
|
|
||||||
Ok(nombre) => {
|
|
||||||
assert_eq!(nombre, a*b+(c-d)/e, "Calcul d'expression (entier) donne un mauvais résultat : {}", nombre);
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Calcul d'expression (entier) échoué, avec l'erreur : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(raison) => {
|
|
||||||
panic!("Détermination d'expression (entier) échouée : {}", raison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn erreur_calcul_nombre() {
|
|
||||||
let pendragon = pendragon::Pendragon::nouveau();
|
|
||||||
let textes_invalide = vec![
|
|
||||||
"un un fois un",
|
|
||||||
"un plus fois un",
|
|
||||||
"un moins divisé par un",
|
|
||||||
"un fois un ouvre la parenthèse un plus un ferme la parenthèse",
|
|
||||||
"un fois ouvre la parenthèse plus un plus un ferme la parenthèse",
|
|
||||||
"un fois ouvre la parenthèse un plus un fois ferme la parenthèse",
|
|
||||||
"un fois ouvre la parenthèse un plus un ferme la parenthèse un",
|
|
||||||
];
|
|
||||||
for texte in textes_invalide {
|
|
||||||
let Err(raison) = pendragon.elements_nombre(texte) else {
|
|
||||||
panic!("Devrait détecter une erreur pour '{}'", texte);
|
|
||||||
};
|
|
||||||
let ErreurPendragon::OrdreCalculEntier(_,_,_) = raison else {
|
|
||||||
panic!("Devrait détecter une erreur de calcul entier pour '{}', a déclenché : {}", texte, raison);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn nombre_invalide_et() {
|
|
||||||
let pendragon = pendragon::Pendragon::nouveau();
|
|
||||||
let Err(raison) = pendragon.elements_nombre("et") else {
|
|
||||||
panic!("Devrait détecter une erreur pour 'et'");
|
|
||||||
};
|
|
||||||
let ErreurPendragon::NombreInvalide(_) = raison else {
|
|
||||||
panic!("Devrait détecter une erreur de nombre invalide pour 'et', a déclenché : {}", raison);
|
|
||||||
};
|
|
||||||
}
|
|
34
src/main.rs
34
src/main.rs
|
@ -4,9 +4,6 @@ use std::time::Instant;
|
||||||
|
|
||||||
mod pendragon;
|
mod pendragon;
|
||||||
use pendragon::*;
|
use pendragon::*;
|
||||||
mod sophie;
|
|
||||||
mod debug;
|
|
||||||
use debug::display;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let arguments: Vec<String> = env::args().collect();
|
let arguments: Vec<String> = env::args().collect();
|
||||||
|
@ -16,8 +13,7 @@ fn main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let mode_debug = arguments.contains(&"-d".to_string());
|
let debug_mode = arguments.contains(&"--debug".to_string());
|
||||||
let mode_interprete = arguments.contains(&"-i".to_string());
|
|
||||||
|
|
||||||
let chemin_de_fichier = &arguments[1];
|
let chemin_de_fichier = &arguments[1];
|
||||||
let mut pendragon = Pendragon::nouveau();
|
let mut pendragon = Pendragon::nouveau();
|
||||||
|
@ -25,33 +21,31 @@ fn main() {
|
||||||
let lecture = fs::read_to_string(chemin_de_fichier);
|
let lecture = fs::read_to_string(chemin_de_fichier);
|
||||||
|
|
||||||
if let Err(raison) = lecture {
|
if let Err(raison) = lecture {
|
||||||
eprintln!("{}Fichier illisible :{} {}", display::TEXTE_ROUGE, raison, display::TEXTE_NORMAL);
|
eprintln!("Fichier illisible : {}", raison);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
display::message_compilation(chemin_de_fichier);
|
println!("# Compilation de '{}'.", chemin_de_fichier);
|
||||||
let debut = Instant::now();
|
let debut = Instant::now();
|
||||||
if let Err(raison) = pendragon.compile(lecture.unwrap()) {
|
if let Err(raison) = pendragon.compile(lecture.unwrap()) {
|
||||||
for erreur in raison {
|
eprintln!("\n{}", raison);
|
||||||
eprintln!("\n{}", erreur);
|
eprintln!("\n# Échec de la compilation.");
|
||||||
}
|
|
||||||
display::message_compilation_echec();
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
display::message_compilation_ok(debut.elapsed());
|
println!("# Compilation Ok. ({:.2?})\n", debut.elapsed());
|
||||||
|
|
||||||
if mode_debug {
|
if debug_mode {
|
||||||
println!("\n{}\n", pendragon.programme);
|
println!("{}\n", pendragon.programme);
|
||||||
}
|
}
|
||||||
if !mode_interprete {
|
|
||||||
return
|
|
||||||
}
|
println!("# Exécution de '{}'.\n", chemin_de_fichier);
|
||||||
display::message_execution(chemin_de_fichier);
|
|
||||||
let debut = Instant::now();
|
let debut = Instant::now();
|
||||||
if let Err(raison) = pendragon.programme.execute() {
|
if let Err(raison) = pendragon.programme.execute() {
|
||||||
eprintln!("\nErreur : {}", raison);
|
eprintln!("\nErreur : {}", raison);
|
||||||
display::message_execution_echec();
|
eprintln!("\n# Échec de l'exécution.");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
display::message_execution_ok(debut.elapsed());
|
|
||||||
|
println!("\n# Exécution Ok. ({:.2?})", debut.elapsed());
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,24 +170,17 @@ impl Pendragon {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ajoute_comparaison_membre(&self, comparaison: &mut Comparaison, texte: &str) -> Result<(), ErreurPendragon> {
|
pub fn ajoute_comparaison_membre(&self, comparaison: &mut Comparaison, texte: &str) -> Result<(), ErreurPendragon> {
|
||||||
let mut membre: Vec<Element> = vec![];
|
let membre = if let Ok(elements_nombre) = self.elements_nombre(texte) {
|
||||||
match self.elements_nombre(texte) {
|
elements_nombre
|
||||||
Ok(elements_nombre) => membre = elements_nombre,
|
} else if let Ok(elements_booleen) = self.elements_booleen(texte) {
|
||||||
Err(raison) => if let ErreurPendragon::OrdreCalculEntier(_,_,_) = raison {return Err(raison)},
|
elements_booleen
|
||||||
}
|
} else if let Ok(elements_texte) = self.elements_texte(texte) {
|
||||||
if membre.is_empty() {
|
elements_texte
|
||||||
match self.elements_booleen(texte) {
|
} else {
|
||||||
Ok(elements_booleen) => membre = elements_booleen,
|
return Err(ErreurPendragon::MauvaisArgument(texte.to_string()));
|
||||||
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 {
|
let Some(element) = membre.first() else {
|
||||||
return Err(ErreurPendragon::MauvaisArgument(texte.to_string()))
|
return Err(ErreurPendragon::ComparaisonInvalide("il n'y a pas de d'élément dans le membre ajouté".into()))
|
||||||
};
|
};
|
||||||
if comparaison.type_comparaison.is_none() {
|
if comparaison.type_comparaison.is_none() {
|
||||||
comparaison.membre_a = membre;
|
comparaison.membre_a = membre;
|
||||||
|
@ -213,6 +206,73 @@ fn compare_parentheses(strings: &Vec<String>) -> (usize, usize) {
|
||||||
(ouvre_count, ferme_count)
|
(ouvre_count, ferme_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn affiche_booleen(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<String, ErreurPendragon> {
|
||||||
|
let booleen = calcule_booleen(expression.clone(), variables)?;
|
||||||
|
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 {
|
||||||
|
return Err(ErreurPendragon::MauvaisType(nom.into(), variable.type_element().nom(), "booleen".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Element::Comparaison(comparaison) = element {
|
||||||
|
pile.push(comparaison.calcule(variables)?);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
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("il reste plusieurs éléments dans la pile".into()))
|
||||||
|
}
|
||||||
|
Ok(pile[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn booleen_comme_texte(booleen: bool) -> String {
|
||||||
|
if booleen {
|
||||||
|
"vrai".into()
|
||||||
|
} else {
|
||||||
|
"faux".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn texte_comme_booleen(texte: &str) -> Result<Element, ErreurPendragon> {
|
pub fn texte_comme_booleen(texte: &str) -> Result<Element, ErreurPendragon> {
|
||||||
match texte {
|
match texte {
|
||||||
"vrai" => Ok(Element::Booleen(true)),
|
"vrai" => Ok(Element::Booleen(true)),
|
||||||
|
@ -233,3 +293,173 @@ pub fn texte_comme_comparaison(texte: &str) -> Result<TypeComparaison, ErreurPen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn conversion_booleen_texte() {
|
||||||
|
for b in [true, false].iter() {
|
||||||
|
let texte = booleen_comme_texte(*b); // Convert number to text
|
||||||
|
match texte_comme_booleen(&texte) { // Convert text back to number
|
||||||
|
Ok(booleen) => {
|
||||||
|
assert_eq!(Element::Booleen(*b), booleen, "Booleen inexact : {}, texte : {}", b, texte);
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Conversion échouée pour : {}, avec l'erreur : {}", b, raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn calcul_booleen() {
|
||||||
|
let pendragon = Pendragon::nouveau();
|
||||||
|
let mut configurations = Vec::new();
|
||||||
|
for b1 in [true, false] {
|
||||||
|
for b2 in [true, false] {
|
||||||
|
for b3 in [true, false] {
|
||||||
|
for b4 in [true, false] {
|
||||||
|
for b5 in [true, false] {
|
||||||
|
configurations.push((b1, b2, b3, b4, b5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for configuration in configurations {
|
||||||
|
let possible_expression = pendragon.elements_booleen(&format!("{} et non ouvre la parenthèse {} ou non {} ferme la parenthèse ou non {} et {}",
|
||||||
|
booleen_comme_texte(configuration.0),
|
||||||
|
booleen_comme_texte(configuration.1),
|
||||||
|
booleen_comme_texte(configuration.2),
|
||||||
|
booleen_comme_texte(configuration.3),
|
||||||
|
booleen_comme_texte(configuration.4)));
|
||||||
|
match possible_expression {
|
||||||
|
Ok(expression) => {
|
||||||
|
match calcule_booleen(expression, &HashMap::new()) {
|
||||||
|
Ok(booleen) => {
|
||||||
|
let resultat = configuration.0 && !(configuration.1 || !configuration.2) || !configuration.3 && configuration.4;
|
||||||
|
assert_eq!(booleen, resultat, "Calcul d'expression (booleen) donne un mauvais résultat : {}", booleen);
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Calcul d'expression (booleen) échoué, avec l'erreur : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Détermination d'expression (booleen) échouée : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn comparaison_booleen() {
|
||||||
|
let pendragon = Pendragon::nouveau();
|
||||||
|
for (a, b) in [(1, 4), (2, 2), (3, 1), (0, 3)] {
|
||||||
|
let possible_expressions = vec![
|
||||||
|
pendragon.elements_booleen(&format!("non six plus {} est supérieur à deux fois {}", nombre::nombre_comme_texte(a), nombre::nombre_comme_texte(b))),
|
||||||
|
pendragon.elements_booleen(&format!("six plus {} est inférieur à deux fois {}", nombre::nombre_comme_texte(a), nombre::nombre_comme_texte(b))),
|
||||||
|
pendragon.elements_booleen(&format!("six plus {} est supérieur ou égal à deux fois {}", nombre::nombre_comme_texte(a), nombre::nombre_comme_texte(b))),
|
||||||
|
pendragon.elements_booleen(&format!("non six plus {} est inférieur ou égal à deux fois {}", nombre::nombre_comme_texte(a), nombre::nombre_comme_texte(b))),
|
||||||
|
pendragon.elements_booleen(&format!("non \"deux\" est égal à \"{}\"", nombre::nombre_comme_texte(a))),
|
||||||
|
pendragon.elements_booleen(&format!("\"trois\" est différent de \"{}\"", nombre::nombre_comme_texte(a))),
|
||||||
|
];
|
||||||
|
let bonne_reponses = vec![
|
||||||
|
!(6+a > 2*b),
|
||||||
|
(6+a < 2*b),
|
||||||
|
(6+a >= 2*b),
|
||||||
|
!(6+a <= 2*b),
|
||||||
|
!(a == 2),
|
||||||
|
(a != 3),
|
||||||
|
];
|
||||||
|
for index in 0..possible_expressions.len() {
|
||||||
|
match &possible_expressions[index] {
|
||||||
|
Ok(expression) => {
|
||||||
|
match calcule_booleen(expression.clone(), &HashMap::new()) {
|
||||||
|
Ok(booleen) => {
|
||||||
|
let reponse = bonne_reponses[index];
|
||||||
|
assert_eq!(booleen, reponse, "Calcul d'expression (booleen) n°{} ({},{}) donne un mauvais résultat : {}, attendais {}", index, a, b, booleen, reponse);
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Calcul d'expression (booleen) échoué, avec l'erreur : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Détermination d'expression (booleen) échouée : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn combinaison_booleen() {
|
||||||
|
let pendragon = Pendragon::nouveau();
|
||||||
|
for a in 0..5 {
|
||||||
|
for b in 0..5 {
|
||||||
|
for c in 0..5 {
|
||||||
|
for d in 1..5 {
|
||||||
|
for e in 0..5 {
|
||||||
|
let possible_expression = pendragon.elements_booleen(&format!("non ouvre la parenthèse six plus {} ferme la parenthèse est supérieur à deux fois {} et ouvre la parenthèse {} divisé par deux est inférieur à ouvre la parenthèse {} moins un ferme la parenthèse ou non \"deux\" est égal à \"{}\" ferme la parenthèse",
|
||||||
|
nombre::nombre_comme_texte(a),
|
||||||
|
nombre::nombre_comme_texte(b),
|
||||||
|
nombre::nombre_comme_texte(c),
|
||||||
|
nombre::nombre_comme_texte(d),
|
||||||
|
nombre::nombre_comme_texte(e),
|
||||||
|
));
|
||||||
|
let bonne_reponse = !((6+a) > 2*b) && (c/2 < (d-1) || !(e == 2));
|
||||||
|
match possible_expression {
|
||||||
|
Ok(expression) => {
|
||||||
|
match calcule_booleen(expression.clone(), &HashMap::new()) {
|
||||||
|
Ok(booleen) => {
|
||||||
|
assert_eq!(booleen, bonne_reponse, "Calcul d'expression (booleen) ({},{},{},{},{}) donne un mauvais résultat : {}, attendais {}", a, b, c, d, e, booleen, bonne_reponse);
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Calcul d'expression (booleen) échoué, avec l'erreur : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Détermination d'expression (booleen) échouée : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn erreur_calcul_booleen() {
|
||||||
|
let pendragon = Pendragon::nouveau();
|
||||||
|
let textes_invalide = vec![
|
||||||
|
"et faux",
|
||||||
|
"vrai et et faux",
|
||||||
|
"vrai ou ou faux",
|
||||||
|
"vrai et vrai faux",
|
||||||
|
"vrai et faux vrai",
|
||||||
|
"vrai et faux ouvre la parenthèse vrai ou faux ferme la parenthèse",
|
||||||
|
"vrai et ouvre la parenthèse et vrai ou faux ferme la parenthèse",
|
||||||
|
"vrai et ouvre la parenthèse vrai ou faux et ferme la parenthèse",
|
||||||
|
"vrai et ouvre la parenthèse vrai ou faux ferme la parenthèse vrai",
|
||||||
|
];
|
||||||
|
for texte in textes_invalide {
|
||||||
|
let Err(raison) = pendragon.elements_booleen(texte) else {
|
||||||
|
panic!("Devrait détecter une erreur pour '{}'", texte);
|
||||||
|
};
|
||||||
|
let ErreurPendragon::OrdreCalculBooleen(_,_,_) = raison else {
|
||||||
|
panic!("Devrait détecter une erreur de calcul booléen pour '{}', a déclenché : {}", texte, raison);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
159
src/pendragon/debug.rs
Normal file
159
src/pendragon/debug.rs
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn raison(&self) -> ErreurPendragon {
|
||||||
|
self.erreur.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl fmt::Display for ErreurCompilation {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
||||||
|
write!(f, "Erreur ligne {} : {}", self.index_ligne + 1, self.erreur)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
pub enum ErreurPendragon {
|
||||||
|
CommandeInconnue(String),
|
||||||
|
ManqueArgument,
|
||||||
|
MauvaisArgument(String),
|
||||||
|
ManquePonctuation,
|
||||||
|
|
||||||
|
NombreInvalide(String),
|
||||||
|
CalculEntier(String),
|
||||||
|
OrdreCalculEntier(String, String, String),
|
||||||
|
|
||||||
|
TexteInvalide(String),
|
||||||
|
|
||||||
|
BooleenInvalide(String),
|
||||||
|
ComparaisonInvalide(String),
|
||||||
|
CalculBooleen(String),
|
||||||
|
OrdreCalculBooleen(String, String, String),
|
||||||
|
|
||||||
|
VariableInconnue(String),
|
||||||
|
MauvaisType(String, String, String),
|
||||||
|
|
||||||
|
Lecture(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::MauvaisArgument(message) => write!(f, "La commande a reçu un mauvais argument, {}.", message),
|
||||||
|
Self::ManquePonctuation => write!(f, "Il manque la ponctuation de la phrase."),
|
||||||
|
|
||||||
|
Self::NombreInvalide(nombre) => write!(f, "Le nombre \"{}\" est mal orthographié.", nombre),
|
||||||
|
Self::CalculEntier(raison) => write!(f, "Calcul entier échoué, {}.", raison),
|
||||||
|
Self::OrdreCalculEntier(manque, precedent, suivant) => write!(f, "Calcul entier échoué, il manque un {} entre '{}' et '{}'.", manque, precedent, suivant),
|
||||||
|
|
||||||
|
Self::TexteInvalide(raison) => write!(f, "Le texte est invalide, {}.", raison),
|
||||||
|
|
||||||
|
Self::BooleenInvalide(booleen) => write!(f, "Le booleen \"{}\" est invalide.", booleen),
|
||||||
|
Self::CalculBooleen(raison) => write!(f, "Calcul booleen échoué, {}.", raison),
|
||||||
|
Self::ComparaisonInvalide(raison) => write!(f, "La comparaison est invalide, {}.", raison),
|
||||||
|
Self::OrdreCalculBooleen(manque, precedent, suivant) => write!(f, "Calcul boolen échoué, il manque un {} entre '{}' et '{}'.", manque, precedent, suivant),
|
||||||
|
|
||||||
|
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::Lecture(raison) => write!(f, "Lecture d'entrées utilisateur impossible : {}.", 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 Element {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
||||||
|
match self {
|
||||||
|
Self::Entier(nombre) => write!(f, "{}", nombre::nombre_comme_texte(*nombre)),
|
||||||
|
Self::Texte(texte) => write!(f, "\"{}\"", texte),
|
||||||
|
Self::Booleen(booleen) => write!(f, "{}", booleen::booleen_comme_texte(*booleen)),
|
||||||
|
Self::Variable(nom, type_variable) => write!(f, "{}:{}", nom, type_variable.nom()),
|
||||||
|
Self::Operateur(operateur) => write!(f, "{}", operateur),
|
||||||
|
Self::Comparaison(comparaison) => write!(f, "{}.", comparaison),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Comparaison {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
||||||
|
let mut texte_membre_a: String = String::new();
|
||||||
|
for element in &self.membre_a {
|
||||||
|
texte_membre_a += &format!("{} ", element);
|
||||||
|
}
|
||||||
|
let mut texte_membre_b: String = String::new();
|
||||||
|
for element in &self.membre_b {
|
||||||
|
texte_membre_b += &format!(" {}", element);
|
||||||
|
}
|
||||||
|
write!(f, "({}{:?}{})",
|
||||||
|
texte_membre_a,
|
||||||
|
self.type_comparaison,
|
||||||
|
texte_membre_b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TypeComparaison {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
||||||
|
match self {
|
||||||
|
Self::Egal => write!(f, "égal à"),
|
||||||
|
Self::Different => write!(f, "différent de"),
|
||||||
|
Self::SuperieurEgal => write!(f, "supérieur ou égal à"),
|
||||||
|
Self::InferieurEgal => write!(f, "inférieur ou égal à"),
|
||||||
|
Self::Superieur => write!(f, "supérieur à"),
|
||||||
|
Self::Inferieur => write!(f, "inférieur à"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Operateur {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {//'
|
||||||
|
match self {
|
||||||
|
Self::Ou => write!(f, "ou"),
|
||||||
|
Self::Et => write!(f, "et"),
|
||||||
|
Self::Non => write!(f, "non"),
|
||||||
|
Self::ParentheseBooleen => write!(f, "["),
|
||||||
|
Self::Puis => write!(f, ";"),
|
||||||
|
Self::Plus => write!(f, "+"),
|
||||||
|
Self::Moins => write!(f, "-"),
|
||||||
|
Self::Fois => write!(f, "*"),
|
||||||
|
Self::Divise => write!(f, "/"),
|
||||||
|
Self::ParentheseEntier => write!(f, "("),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,11 +1,12 @@
|
||||||
use crate::display::ErreurPendragon;
|
use std::collections::HashMap;
|
||||||
use crate::display::ErreurCompilation;
|
|
||||||
|
|
||||||
pub mod nombre;
|
pub mod nombre;
|
||||||
pub mod texte;
|
pub mod texte;
|
||||||
pub mod booleen;
|
pub mod booleen;
|
||||||
pub mod structure;
|
pub mod structure;
|
||||||
use structure::*;
|
use structure::*;
|
||||||
|
pub mod debug;
|
||||||
|
use debug::*;
|
||||||
|
|
||||||
pub struct Pendragon {
|
pub struct Pendragon {
|
||||||
pub programme: Programme,
|
pub programme: Programme,
|
||||||
|
@ -18,67 +19,30 @@ impl Pendragon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(&mut self, contenu: String) -> Result<(), Vec<ErreurCompilation>> {
|
pub fn compile(&mut self, contenu: String) -> Result<(), ErreurCompilation> {
|
||||||
let texte: Vec<&str> = contenu.split('\n').collect();
|
let texte: Vec<&str> = contenu.split('\n').collect();
|
||||||
let mut erreurs: Vec<ErreurCompilation> = vec![];
|
|
||||||
let mut indentation_niveau: usize = 0;
|
|
||||||
let mut pile_bloc: Vec<Bloc> = vec![];
|
|
||||||
|
|
||||||
for (index_ligne, ligne) in texte.iter().enumerate() {
|
for (index_ligne, ligne) in texte.iter().enumerate() {
|
||||||
let indentation_ligne = ligne.chars().take_while(|&c| c == '\t').count();
|
|
||||||
let ligne = ligne.trim();
|
let ligne = ligne.trim();
|
||||||
let phrases: Vec<&str> = ligne.split_inclusive(|c| c == ',' || c == '.').collect();
|
let phrases: Vec<&str> = ligne.split_inclusive(|c| c == ',' || c == '.').collect();
|
||||||
let Some(derniere_phrase) = phrases.last() else {
|
let Some(derniere_phrase) = phrases.last() else {
|
||||||
continue
|
continue
|
||||||
};
|
};
|
||||||
if !derniere_phrase.ends_with('.') && !derniere_phrase.ends_with(',') {
|
if !derniere_phrase.ends_with('.') && !derniere_phrase.ends_with(',') {
|
||||||
erreurs.push(ErreurCompilation::nouvelle(index_ligne, ligne.into(), ErreurPendragon::ManquePonctuation))
|
return Err(ErreurCompilation::nouvelle(index_ligne, 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 {
|
for phrase in phrases {
|
||||||
if phrase.ends_with(".") {
|
if phrase.ends_with(".") {
|
||||||
if phrase.replace(" ", "").starts_with("NotaBene:") {
|
if phrase.replace(" ", "").starts_with("NotaBene:") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
match self.compile_commande(&phrase[..phrase.len() - 1]) {
|
match self.compile_commande(&phrase[..phrase.len() - 1]) {
|
||||||
Ok(commande) => {
|
Ok(commande) => self.programme.ajoute_commande(commande),
|
||||||
if let Some(bloc_actuel) = pile_bloc.last_mut() {
|
Err(raison) => return Err(ErreurCompilation::nouvelle(index_ligne, raison)),
|
||||||
bloc_actuel.ajoute_commande(commande);
|
|
||||||
} else {
|
|
||||||
self.programme.ajoute_commande(commande);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(raison) => erreurs.push(ErreurCompilation::nouvelle(index_ligne, ligne.into(), raison)),
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match self.compile_bloc(&phrase[..phrase.len() - 1]) {
|
println!("todo : {}", phrase);
|
||||||
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)], false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
indentation_niveau += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if erreurs.len() > 0 {
|
|
||||||
return Err(erreurs)
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -89,7 +53,7 @@ impl Pendragon {
|
||||||
if parties.len() == 1 {
|
if parties.len() == 1 {
|
||||||
return Err(ErreurPendragon::ManqueArgument)
|
return Err(ErreurPendragon::ManqueArgument)
|
||||||
}
|
}
|
||||||
if contient_mot_cle(parties[1]) {
|
if parties[1].contains("Définis") || parties[1].contains("Modifie") || parties[1].contains("Affiche") || parties[1].contains("Demande") {
|
||||||
return Err(ErreurPendragon::ManquePonctuation)
|
return Err(ErreurPendragon::ManquePonctuation)
|
||||||
}
|
}
|
||||||
match parties[0] {
|
match parties[0] {
|
||||||
|
@ -101,23 +65,6 @@ impl Pendragon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_bloc(&mut self, phrase: &str) -> Result<Bloc, ErreurPendragon> {
|
|
||||||
let phrase = phrase.trim().replace("Tant que", "Tant-que");
|
|
||||||
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] {
|
|
||||||
"Tant-que" => Ok(Bloc::nouveau(self.elements_booleen(parties[1])?, true)),
|
|
||||||
"Si" => Ok(Bloc::nouveau(self.elements_booleen(parties[1])?, false)),
|
|
||||||
autre => Err(ErreurPendragon::BlocInconnu(autre.into())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn affiche(&self, arguments: &str) -> Result<Commande, ErreurPendragon> {
|
fn affiche(&self, arguments: &str) -> Result<Commande, ErreurPendragon> {
|
||||||
Ok(Commande::Affiche(self.elements_texte(arguments)?))
|
Ok(Commande::Affiche(self.elements_texte(arguments)?))
|
||||||
}
|
}
|
||||||
|
@ -152,14 +99,6 @@ 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> {
|
fn nom_de_variable(arguments: &str, separateur: &str) -> Result<(String, String), ErreurPendragon> {
|
||||||
let parties = if separateur == "" {
|
let parties = if separateur == "" {
|
||||||
vec![arguments, ""]
|
vec![arguments, ""]
|
||||||
|
@ -187,6 +126,7 @@ pub fn format_de_variable(nom: &str) -> bool {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use std::collections::HashMap;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -204,11 +144,8 @@ mod test {
|
||||||
];
|
];
|
||||||
for commentaire in commentaires {
|
for commentaire in commentaires {
|
||||||
match pendragon.compile(commentaire.into()) {
|
match pendragon.compile(commentaire.into()) {
|
||||||
Ok(_) => assert_eq!(pendragon.programme.contenu.len(), 0, "Le commentaire '{}' ne devrait pas générer de commande", commentaire),
|
Ok(_) => assert_eq!(pendragon.programme.commandes.len(), 0, "Le commentaire '{}' ne devrait pas générer de commande", commentaire),
|
||||||
Err(erreurs) => {
|
Err(raison) => panic!("Erreur de compilation du commentaire '{}' : {}", commentaire, raison)
|
||||||
let affichage_erreurs = erreurs.iter().map(|item| format!("{}", item.raison())).collect::<Vec<_>>().join("\n\n");
|
|
||||||
panic!("Erreur de compilation du commentaire '{}' : \n{}", commentaire, affichage_erreurs)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,95 +164,32 @@ mod test {
|
||||||
"NNotaBene:ceci n'est pas un commentaire."
|
"NNotaBene:ceci n'est pas un commentaire."
|
||||||
];
|
];
|
||||||
for commentaire in commentaires {
|
for commentaire in commentaires {
|
||||||
let Err(erreurs) = pendragon.compile(commentaire.into()) else {
|
let Err(erreur) = pendragon.compile(commentaire.into()) else {
|
||||||
panic!("Ne devrait pas pouvoir compiler un commentaire invalide '{}'", commentaire);
|
panic!("Ne devrait pas pouvoir compiler un commentaire invalide '{}'", commentaire);
|
||||||
};
|
};
|
||||||
if erreurs.len() > 1 {
|
let ErreurPendragon::CommandeInconnue(_) = erreur.raison() else {
|
||||||
let affichage_erreurs = erreurs.iter().map(|item| format!("{}", item.raison())).collect::<Vec<_>>().join("\n\n");
|
panic!("Erreur inattendue de compilation du commentaire '{}' : {}", commentaire, erreur.raison());
|
||||||
panic!("Plus d'erreurs que prévu pour le commentaire '{}' : {:?}", commentaire, affichage_erreurs)
|
|
||||||
}
|
|
||||||
let ErreurPendragon::CommandeInconnue(_) = erreurs[0].raison() else {
|
|
||||||
panic!("Erreur inattendue de compilation du commentaire '{}' : {}", commentaire, erreurs[0].raison());
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ponctuation_valide() {
|
fn ponctuation_valide() {
|
||||||
let mut pendragon = Pendragon::nouveau();
|
panic!("todo");
|
||||||
let texte = "aah.\noooh.uuuh,\nna,\nbududu.bababa.\naaaaaaaaaaa,sssssss,";
|
|
||||||
let Err(erreurs) = pendragon.compile(texte.into()) else {
|
|
||||||
panic!("Il devrait y avoir des erreurs");
|
|
||||||
};
|
|
||||||
for erreur in erreurs {
|
|
||||||
if let ErreurPendragon::ManquePonctuation = erreur.raison() {
|
|
||||||
panic!("Erreur : manque ponctuation");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ponctuation_invalide() {
|
fn ponctuation_invalide() {
|
||||||
let mut pendragon = Pendragon::nouveau();
|
panic!("todo");
|
||||||
let textes = [
|
|
||||||
"Aaaaa",
|
|
||||||
"aaaa.\nooooo\n",
|
|
||||||
"aaaa Définis."
|
|
||||||
];
|
|
||||||
for texte in textes {
|
|
||||||
let Err(erreurs) = pendragon.compile(texte.into()) else {
|
|
||||||
panic!("Ne devrait pas pouvoir compiler un texte invalide '{}'", texte);
|
|
||||||
};
|
|
||||||
let mut manque_ponctuation = false;
|
|
||||||
for erreur in erreurs {
|
|
||||||
if let ErreurPendragon::ManquePonctuation = erreur.raison() {
|
|
||||||
manque_ponctuation = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !manque_ponctuation {
|
|
||||||
panic!("Il devrait y avoir une erreur de ponctuation dans le texte '{}'", texte);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn commande_valide() {
|
fn commande_valide() {
|
||||||
let mut pendragon = Pendragon::nouveau();
|
panic!("todo");
|
||||||
let texte = "Affiche.\nDemande.\nModifie.Définis.";
|
|
||||||
let Err(erreurs) = pendragon.compile(texte.into()) else {
|
|
||||||
panic!("Il devrait y avoir des erreurs");
|
|
||||||
};
|
|
||||||
for erreur in erreurs {
|
|
||||||
if let ErreurPendragon::CommandeInconnue(_) = erreur.raison() {
|
|
||||||
panic!("Erreur : commande invalide");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn commande_invalide() {
|
fn commande_invalide() {
|
||||||
let mut pendragon = Pendragon::nouveau();
|
panic!("todo");
|
||||||
let textes = [
|
|
||||||
"Definis a.",
|
|
||||||
"définis b.",
|
|
||||||
"modifie c.",
|
|
||||||
"affiche d.",
|
|
||||||
"aaaa e."
|
|
||||||
];
|
|
||||||
for texte in textes {
|
|
||||||
let Err(erreurs) = pendragon.compile(texte.into()) else {
|
|
||||||
panic!("Ne devrait pas pouvoir compiler un texte invalide '{}'", texte);
|
|
||||||
};
|
|
||||||
let mut commande_inconnue = false;
|
|
||||||
for erreur in &erreurs {
|
|
||||||
if let ErreurPendragon::CommandeInconnue(_) = erreur.raison() {
|
|
||||||
commande_inconnue = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !commande_inconnue {
|
|
||||||
let affichage_erreurs = erreurs.iter().map(|item| format!("{}", item.raison())).collect::<Vec<_>>().join("\n\n");
|
|
||||||
panic!("La commande devrait être inconnue '{}', erreurs : \n{}", texte, affichage_erreurs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub 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"];
|
||||||
pub 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"];
|
||||||
pub const NOMS_DIZAINES: [&str; 9] = ["", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "x", "quatre-vingts"];
|
const NOMS_DIZAINES: [&str; 9] = ["", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "x", "quatre-vingts"];
|
||||||
pub const NOMS_SEPARATEURS: [&str; 7] = ["", "mille", "million", "milliard", "billion", "billiard", "trillion"];
|
const NOMS_SEPARATEURS: [&str; 7] = ["", "mille", "million", "milliard", "billion", "billiard", "trillion"];
|
||||||
pub const UNION: &str = "-";
|
const UNION: &str = "-";
|
||||||
|
|
||||||
impl Pendragon {
|
impl Pendragon {
|
||||||
pub fn elements_nombre(&self, arguments: &str) -> Result<Vec<Element>, ErreurPendragon> {
|
pub fn elements_nombre(&self, arguments: &str) -> Result<Vec<Element>, ErreurPendragon> {
|
||||||
|
@ -112,6 +112,143 @@ impl Pendragon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn affiche_nombre(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<String, ErreurPendragon> {
|
||||||
|
let nombre = calcule_nombre(expression.clone(), variables)?;
|
||||||
|
Ok(nombre_comme_texte(nombre))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calcule_nombre(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<usize, ErreurPendragon> {
|
||||||
|
let mut pile: Vec<usize> = Vec::new();
|
||||||
|
|
||||||
|
for element in expression {
|
||||||
|
if let Element::Entier(nombre) = element {
|
||||||
|
pile.push(nombre);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Element::Variable(nom, _) = element {
|
||||||
|
let Some(variable) = variables.get(&nom) else {
|
||||||
|
return Err(ErreurPendragon::VariableInconnue(nom.into()))
|
||||||
|
};
|
||||||
|
if let Element::Entier(nombre) = variable {
|
||||||
|
pile.push(*nombre);
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
return Err(ErreurPendragon::MauvaisType(nom.into(), variable.type_element().nom(), "entier".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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_a);
|
||||||
|
}
|
||||||
|
Operateur::Moins => {
|
||||||
|
if nombre_b < nombre_a {
|
||||||
|
return Err(ErreurPendragon::CalculEntier(format!("a essayé de soustraire '{}' à '{}'", nombre::nombre_comme_texte(nombre_a), nombre::nombre_comme_texte(nombre_b))))
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
if nombre == 0 {
|
||||||
|
return "zéro".to_string()
|
||||||
|
}
|
||||||
|
if nombre >= 10usize.pow(18) {
|
||||||
|
return "infini".to_string()
|
||||||
|
}
|
||||||
|
let mut groupes: Vec<usize> = vec![];
|
||||||
|
let mut nombre = nombre;
|
||||||
|
while nombre > 0 {
|
||||||
|
groupes.insert(0, nombre % 1000);
|
||||||
|
nombre /= 1000;
|
||||||
|
}
|
||||||
|
let mut chaine: String = "".to_string();
|
||||||
|
|
||||||
|
for index in 0..groupes.len() {
|
||||||
|
if groupes[index] == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let pluriel: &str = if (groupes.len() - index - 1 > 1) && groupes[index] > 1 {
|
||||||
|
"s"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
if index < groupes.len() - 1 {
|
||||||
|
let union = if index > 0 {UNION} else {""};
|
||||||
|
let chiffre = if groupes.len() - index - 1 == 1 && groupes[index] == 1 { // un mille
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
petit_nombre_comme_texte(groupes[index]) + UNION
|
||||||
|
};
|
||||||
|
chaine += &format!("{}{}{}{}",
|
||||||
|
union,
|
||||||
|
chiffre,
|
||||||
|
NOMS_SEPARATEURS[groupes.len() - index - 1],
|
||||||
|
pluriel,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let union = if index > 0 {UNION} else {""};
|
||||||
|
chaine += union;
|
||||||
|
chaine += &petit_nombre_comme_texte(groupes[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chaine
|
||||||
|
}
|
||||||
|
|
||||||
|
fn petit_nombre_comme_texte(nombre: usize) -> String {
|
||||||
|
let nombre = nombre.clamp(0, 999);
|
||||||
|
let centaine = nombre / 100;
|
||||||
|
let dizaine = (nombre % 100) / 10;
|
||||||
|
let unité = nombre % 10;
|
||||||
|
|
||||||
|
let centaine_texte = if centaine > 1 {
|
||||||
|
format!("{}{}cent", NOMS_UNITES[centaine], UNION)
|
||||||
|
} else if centaine > 0 {
|
||||||
|
"cent".to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let décalage_dizaine = if [1, 7, 9].contains(&dizaine) {1} else {0};
|
||||||
|
let dizaine_texte = NOMS_DIZAINES[dizaine - décalage_dizaine];
|
||||||
|
let séparation = if unité == 1 && ![0, 1, 8, 9].contains(&dizaine) {UNION.to_string() + "et"} else {"".to_string()};
|
||||||
|
let unité_texte = if [1, 7, 9].contains(&dizaine) {NOMS_UNITES_DIX[unité]} else {NOMS_UNITES[unité]};
|
||||||
|
|
||||||
|
let mut texte_nombre = format!("{}{}{}{}{}{}", centaine_texte, UNION, dizaine_texte, séparation, UNION, unité_texte);
|
||||||
|
|
||||||
|
while texte_nombre.contains("--") {
|
||||||
|
texte_nombre = texte_nombre.replace("--","-");
|
||||||
|
}
|
||||||
|
if texte_nombre.starts_with("-") {
|
||||||
|
texte_nombre = texte_nombre[1..texte_nombre.len()].to_string();
|
||||||
|
}
|
||||||
|
if texte_nombre.ends_with("-") {
|
||||||
|
texte_nombre = texte_nombre[0..texte_nombre.len()-1].to_string();
|
||||||
|
}
|
||||||
|
texte_nombre
|
||||||
|
}
|
||||||
|
|
||||||
pub fn texte_comme_nombre(texte: &str) -> Result<Element, ErreurPendragon> {
|
pub fn texte_comme_nombre(texte: &str) -> Result<Element, ErreurPendragon> {
|
||||||
if texte == "zéro" {
|
if texte == "zéro" {
|
||||||
return Ok(Element::Entier(0))
|
return Ok(Element::Entier(0))
|
||||||
|
@ -223,3 +360,97 @@ fn texte_comme_petit_nombre(texte: &str) -> Result<usize, ErreurPendragon> {
|
||||||
|
|
||||||
Ok(nombre)
|
Ok(nombre)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn conversion_nombres_texte() {
|
||||||
|
for i in [0, 1, 42, 70, 123, 999, 1031, 1_001_091, 72_036_854_775_807usize, 2345678*987654].iter() {
|
||||||
|
let texte = nombre_comme_texte(*i); // Convert number to text
|
||||||
|
if texte.contains("--") {
|
||||||
|
panic!("Il y a deux tirets pour {} : {}", i, texte);
|
||||||
|
}
|
||||||
|
match texte_comme_nombre(&texte) { // Convert text back to number
|
||||||
|
Ok(nombre) => {
|
||||||
|
assert_eq!(Element::Entier(*i), nombre, "Nombre inexact : {}, texte : {}", i, texte);
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Conversion échouée pour : {}, avec l'erreur : {}", i, raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn calcul_nombre() {
|
||||||
|
let pendragon = Pendragon::nouveau();
|
||||||
|
let a = 2345678;
|
||||||
|
let b = 987654;
|
||||||
|
let c = 34523456;
|
||||||
|
let d = 45678;
|
||||||
|
let e = 2;
|
||||||
|
let possible_expression = pendragon.elements_nombre(&format!("{} fois {} plus ouvre la parenthèse {} moins {} ferme la parenthèse divisé par {}",
|
||||||
|
nombre_comme_texte(a),
|
||||||
|
nombre_comme_texte(b),
|
||||||
|
nombre_comme_texte(c),
|
||||||
|
nombre_comme_texte(d),
|
||||||
|
nombre_comme_texte(e)));
|
||||||
|
match possible_expression {
|
||||||
|
Ok(expression) => {
|
||||||
|
match calcule_nombre(expression, &HashMap::new()) {
|
||||||
|
Ok(nombre) => {
|
||||||
|
assert_eq!(nombre, a*b+(c-d)/e, "Calcul d'expression (entier) donne un mauvais résultat : {}", nombre);
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Calcul d'expression (entier) échoué, avec l'erreur : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Détermination d'expression (entier) échouée : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn erreur_calcul_nombre() {
|
||||||
|
let pendragon = Pendragon::nouveau();
|
||||||
|
let textes_invalide = vec![
|
||||||
|
"un un fois un",
|
||||||
|
"un plus fois un",
|
||||||
|
"un moins divisé par un",
|
||||||
|
"un fois un ouvre la parenthèse un plus un ferme la parenthèse",
|
||||||
|
"un fois ouvre la parenthèse plus un plus un ferme la parenthèse",
|
||||||
|
"un fois ouvre la parenthèse un plus un fois ferme la parenthèse",
|
||||||
|
"un fois ouvre la parenthèse un plus un ferme la parenthèse un",
|
||||||
|
];
|
||||||
|
for texte in textes_invalide {
|
||||||
|
let Err(raison) = pendragon.elements_nombre(texte) else {
|
||||||
|
panic!("Devrait détecter une erreur pour '{}'", texte);
|
||||||
|
};
|
||||||
|
let ErreurPendragon::OrdreCalculEntier(_,_,_) = raison else {
|
||||||
|
panic!("Devrait détecter une erreur de calcul entier pour '{}', a déclenché : {}", texte, raison);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nombre_invalide_et() {
|
||||||
|
let pendragon = Pendragon::nouveau();
|
||||||
|
let Err(raison) = pendragon.elements_nombre("et") else {
|
||||||
|
panic!("Devrait détecter une erreur pour 'et'");
|
||||||
|
};
|
||||||
|
let ErreurPendragon::NombreInvalide(_) = raison else {
|
||||||
|
panic!("Devrait détecter une erreur de nombre invalide pour 'et', a déclenché : {}", raison);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,26 +1,23 @@
|
||||||
|
use std::io;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub struct Programme {
|
pub struct Programme {
|
||||||
pub variables: HashMap<String, TypeElement>,
|
pub variables: HashMap<String, TypeElement>,
|
||||||
pub contenu: Vec<Phrase>,
|
pub commandes: Vec<Commande>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Programme {
|
impl Programme {
|
||||||
pub fn nouveau() -> Self {
|
pub fn nouveau() -> Self {
|
||||||
Self {
|
Self {
|
||||||
variables: HashMap::new(),
|
variables: HashMap::new(),
|
||||||
contenu: vec![],
|
commandes: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ajoute_commande(&mut self, commande: Commande) {
|
pub fn ajoute_commande(&mut self, commande: Commande) {
|
||||||
self.contenu.push(Phrase::Commande(commande));
|
self.commandes.push(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> {
|
pub fn ajoute_variable(&mut self, nom: String, type_variable: TypeElement) -> Result<(), ErreurPendragon> {
|
||||||
|
@ -54,37 +51,35 @@ impl Programme {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Bloc {
|
pub fn execute(&self) -> Result<(), ErreurPendragon> {
|
||||||
pub condition: Vec<Element>,
|
let mut variables_globales: HashMap<String, Element> = HashMap::new();
|
||||||
pub repete: bool,
|
for commande in &self.commandes {
|
||||||
pub contenu: Vec<Phrase>,
|
match commande {
|
||||||
}
|
Commande::Definis(nom, type_element) => {
|
||||||
|
variables_globales.insert(nom.to_string(), type_element.comme_element());
|
||||||
impl Bloc {
|
}
|
||||||
pub fn nouveau(condition: Vec<Element>, repete: bool) -> Self {
|
Commande::Demande(nom) => {
|
||||||
Self {
|
let valeur = variables_globales[nom].type_element().demande_valeur(&nom)?;
|
||||||
condition,
|
variables_globales.insert(nom.to_string(), valeur);
|
||||||
repete,
|
}
|
||||||
contenu: vec![],
|
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)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ajoute_commande(&mut self, commande: Commande) {
|
|
||||||
self.contenu.push(Phrase::Commande(commande));
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
pub fn ajoute_bloc(&mut self, bloc: Bloc) {
|
|
||||||
self.contenu.push(Phrase::Bloc(bloc));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Phrase {
|
|
||||||
Bloc(Bloc),
|
|
||||||
Commande(Commande),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Commande {
|
pub enum Commande {
|
||||||
Definis(String, TypeElement),
|
Definis(String, TypeElement),
|
||||||
Demande(String),
|
Demande(String),
|
||||||
|
@ -132,6 +127,22 @@ impl TypeElement {
|
||||||
Self::Booleen => booleen::texte_comme_booleen(texte),
|
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)]
|
||||||
|
@ -154,6 +165,28 @@ impl Element {
|
||||||
Self::Operateur(operateur) => operateur.type_element(),
|
Self::Operateur(operateur) => operateur.type_element(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compare(&self, element: Element, comparaison: TypeComparaison) -> Result<bool, ErreurPendragon> {
|
||||||
|
if let TypeComparaison::Egal = comparaison {
|
||||||
|
return Ok(*self == element)
|
||||||
|
}
|
||||||
|
if let TypeComparaison::Different = comparaison {
|
||||||
|
return Ok(*self != element)
|
||||||
|
}
|
||||||
|
let Self::Entier(nombre_a) = self else {
|
||||||
|
return Err(ErreurPendragon::ComparaisonInvalide(format!("comparaison numérique avec {}", self)))
|
||||||
|
};
|
||||||
|
let Self::Entier(nombre_b) = element else {
|
||||||
|
return Err(ErreurPendragon::ComparaisonInvalide(format!("comparaison numérique avec {}", element)))
|
||||||
|
};
|
||||||
|
match comparaison {
|
||||||
|
TypeComparaison::SuperieurEgal => Ok(*nombre_a >= nombre_b),
|
||||||
|
TypeComparaison::InferieurEgal => Ok(*nombre_a <= nombre_b),
|
||||||
|
TypeComparaison::Superieur => Ok(*nombre_a > nombre_b),
|
||||||
|
TypeComparaison::Inferieur => Ok(*nombre_a < nombre_b),
|
||||||
|
_ => Err(ErreurPendragon::ComparaisonInvalide("problème de logique".into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -214,6 +247,33 @@ impl Comparaison {
|
||||||
}
|
}
|
||||||
return Err(ErreurPendragon::ComparaisonInvalide(format!("voulait comparer {} avec {}", element.type_element().nom(), type_comparaison)))
|
return Err(ErreurPendragon::ComparaisonInvalide(format!("voulait comparer {} avec {}", element.type_element().nom(), type_comparaison)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn calcule(&self, variables: &HashMap<String, Element>) -> Result<bool, ErreurPendragon> {
|
||||||
|
let Some(ref comparaison) = self.type_comparaison else {
|
||||||
|
return Err(ErreurPendragon::ComparaisonInvalide("la comparaison n'a pas de type".into()))
|
||||||
|
};
|
||||||
|
let Some(element) = self.membre_a.first() else {
|
||||||
|
return Err(ErreurPendragon::ComparaisonInvalide("il n'y a pas de premier membre".into()))
|
||||||
|
};
|
||||||
|
let (membre_a, membre_b) = match element.type_element() {
|
||||||
|
TypeElement::Entier => {
|
||||||
|
let membre_a = Element::Entier(nombre::calcule_nombre(self.membre_a.clone(), variables)?);
|
||||||
|
let membre_b = Element::Entier(nombre::calcule_nombre(self.membre_b.clone(), variables)?);
|
||||||
|
(membre_a, membre_b)
|
||||||
|
}
|
||||||
|
TypeElement::Texte => {
|
||||||
|
let membre_a = Element::Texte(texte::calcule_texte(self.membre_a.clone(), variables)?);
|
||||||
|
let membre_b = Element::Texte(texte::calcule_texte(self.membre_b.clone(), variables)?);
|
||||||
|
(membre_a, membre_b)
|
||||||
|
}
|
||||||
|
TypeElement::Booleen => {
|
||||||
|
let membre_a = Element::Booleen(booleen::calcule_booleen(self.membre_a.clone(), variables)?);
|
||||||
|
let membre_b = Element::Booleen(booleen::calcule_booleen(self.membre_b.clone(), variables)?);
|
||||||
|
(membre_a, membre_b)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(membre_a.compare(membre_b, comparaison.clone())?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
|
137
src/pendragon/tests.rs
Normal file
137
src/pendragon/tests.rs
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
|
||||||
|
|
||||||
|
//#[test]
|
||||||
|
//fn teste_definition_variable() {
|
||||||
|
// let mut sophie = Pendragon::new();
|
||||||
|
// let resultat = sophie.execute_phrase("Définis Element comme entier");
|
||||||
|
// match resultat {
|
||||||
|
// Ok(_) => {
|
||||||
|
// assert_eq!(sophie.variables["Element"], Element::Entier(0), "Element mal définie");
|
||||||
|
// }
|
||||||
|
// Err(raison) => {
|
||||||
|
// panic!("Définition de variable échouée : {}", raison);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//#[test]
|
||||||
|
//fn teste_modification_variable() {
|
||||||
|
// let mut sophie = Pendragon::new();
|
||||||
|
// if let Err(raison) = sophie.execute_phrase("Définis Element comme entier") {
|
||||||
|
// panic!("Définition de variable échouée : {}", raison);
|
||||||
|
// }
|
||||||
|
// let a = 2345678;
|
||||||
|
// let resultat = sophie.execute_phrase(&format!("Modifie Element avec {} ", nombre::nombre_comme_texte(a)));
|
||||||
|
// match resultat {
|
||||||
|
// Ok(_) => {
|
||||||
|
// assert_eq!(sophie.variables["Element"], Element::Entier(a), "Element mal modifiée");
|
||||||
|
// }
|
||||||
|
// Err(raison) => {
|
||||||
|
// panic!("Modification de variable échouée : {}", raison);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//#[test]
|
||||||
|
//fn teste_operation_variable() {
|
||||||
|
// let mut sophie = Pendragon::new();
|
||||||
|
// if let Err(raison) = sophie.execute_phrase("Définis Element comme entier") {
|
||||||
|
// panic!("Définition de variable échouée : {}", raison);
|
||||||
|
// }
|
||||||
|
// let a = 2345678;
|
||||||
|
// if let Err(raison) = sophie.execute_phrase(&format!("Modifie Element avec {} ", nombre::nombre_comme_texte(a))) {
|
||||||
|
// panic!("Modification de variable échouée : {}", raison);
|
||||||
|
// }
|
||||||
|
// let b = 987654;
|
||||||
|
// let resultat = sophie.operation(&format!("Element plus {}", nombre::nombre_comme_texte(b)));
|
||||||
|
// match resultat {
|
||||||
|
// Ok(nombre) => {
|
||||||
|
// assert_eq!(nombre, a+b, "Echec de la somme d'un entier et d'une variable, attendais {}, a reçu {}", a+b, nombre);
|
||||||
|
// }
|
||||||
|
// Err(raison) => {
|
||||||
|
// panic!("Opération de variable échouée : {}", raison);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//#[test]
|
||||||
|
//fn teste_texte() {
|
||||||
|
// let mut sophie = Pendragon::new();
|
||||||
|
// if let Err(raison) = sophie.execute_phrase("Définis A comme entier") {
|
||||||
|
// panic!("Définition de variable échouée : {}", raison);
|
||||||
|
// }
|
||||||
|
// let a = 2345678;
|
||||||
|
// if let Err(raison) = sophie.execute_phrase(&format!("Modifie A avec {} ", nombre::nombre_comme_texte(a))) {
|
||||||
|
// panic!("Modification de variable échouée : {}", raison);
|
||||||
|
// }
|
||||||
|
// if let Err(raison) = sophie.execute_phrase("Définis B comme texte") {
|
||||||
|
// panic!("Définition de variable échouée : {}", raison);
|
||||||
|
// }
|
||||||
|
// if let Err(raison) = sophie.execute_phrase("Modifie B avec \"hello there\", \" general\", \" Kenobi\"") {
|
||||||
|
// panic!("Modification de variable échouée : {}", raison);
|
||||||
|
// }
|
||||||
|
// let resultat = sophie.texte("\"Combo : \", B, \" / \", A plus ouvre la parenthèse un plus cinq ferme la parenthèse fois ouvre la parenthèse huit moins un ferme la parenthèse");
|
||||||
|
//
|
||||||
|
// match resultat {
|
||||||
|
// Ok(texte) => assert_eq!(texte, "Combo : hello there general Kenobi / deux-millions-trois-cent-quarante-cinq-mille-sept-cent-vingt", "Texte mal calculé"),
|
||||||
|
// Err(raison) => panic!("Calcul de texte échoué : {}", raison),
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
// --------------------------------------------- anti-test
|
||||||
|
|
||||||
|
//#[test]
|
||||||
|
//fn teste_redefinition_variable() {
|
||||||
|
// let mut sophie = Pendragon::new();
|
||||||
|
// if let Err(raison) = sophie.execute_phrase("Définis Element comme entier") {
|
||||||
|
// panic!("Définition de variable échouée : {}", raison);
|
||||||
|
// };
|
||||||
|
// let Err(raison) = sophie.execute_phrase("Définis Element comme texte") else {
|
||||||
|
// panic!("Ne devrais pas pouvoir redéfinir une variable");
|
||||||
|
// };
|
||||||
|
// if let ErreurPendragon::MauvaisArgument(ref texte) = raison {
|
||||||
|
// assert_eq!(texte, "la variable \"Element\" existe déjà", "Définition échouée avec erreur imprévue : {}", raison);
|
||||||
|
// } else {
|
||||||
|
// panic!("Définition échouée avec erreur imprévue : {}", raison);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//#[test]
|
||||||
|
//fn teste_echec_modification() {
|
||||||
|
// let mut sophie = Pendragon::new();
|
||||||
|
// let resultat = sophie.execute_phrase("Modifie Element avec deux");
|
||||||
|
// let Err(raison) = resultat else {
|
||||||
|
// panic!("Ne devrais pas pouvoir modifier une variable non définie");
|
||||||
|
// };
|
||||||
|
// if let ErreurPendragon::VariableInconnue(nom) = raison {
|
||||||
|
// assert_eq!(nom, "Element", "Mauvais nom de variable reconnu : {}", nom);
|
||||||
|
// } else {
|
||||||
|
// panic!("Modification échouée avec erreur imprévue : {}", raison);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//#[test]
|
||||||
|
//fn teste_majuscule_variable() {
|
||||||
|
// let mut sophie = Pendragon::new();
|
||||||
|
// let resultat = sophie.execute_phrase("Définis variable comme entier");
|
||||||
|
// let Err(raison) = resultat else {
|
||||||
|
// panic!("Ne devrais pas pouvoir definir une variable sans majuscule");
|
||||||
|
// };
|
||||||
|
// if let ErreurPendragon::MauvaisArgument(explication) = raison {
|
||||||
|
// assert_eq!(explication, "il manque une majuscule à la variable", "Mauvaise explication : {}", explication);
|
||||||
|
// } else {
|
||||||
|
// panic!("Définition échouée avec erreur imprévue : {}", raison);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//#[test]
|
||||||
|
//fn teste_point_phrase() {
|
||||||
|
// let mut sophie = Pendragon::new();
|
||||||
|
// let resultat = sophie.execute("Définis Element comme entier".into());
|
||||||
|
// let Err(raison) = resultat else {
|
||||||
|
// panic!("Ne devrais pas pouvoir faire de commande sans point à la fin");
|
||||||
|
// };
|
||||||
|
// let ErreurPendragon::ManquePoint = raison else {
|
||||||
|
// panic!("Définition échouée avec erreur imprévue : {}", raison);
|
||||||
|
// };
|
||||||
|
//}
|
|
@ -42,6 +42,7 @@ impl Pendragon {
|
||||||
expression.push(Element::Operateur(Operateur::Puis));
|
expression.push(Element::Operateur(Operateur::Puis));
|
||||||
}
|
}
|
||||||
expression.extend(self.puis(&expression, &pile_inconnu)?);
|
expression.extend(self.puis(&expression, &pile_inconnu)?);
|
||||||
|
pile_inconnu = Vec::new();
|
||||||
expression.push(Element::Operateur(Operateur::Puis));
|
expression.push(Element::Operateur(Operateur::Puis));
|
||||||
Ok(expression)
|
Ok(expression)
|
||||||
}
|
}
|
||||||
|
@ -80,3 +81,124 @@ impl Pendragon {
|
||||||
Err(raison)
|
Err(raison)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::Puis = 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)?;
|
||||||
|
pile = Vec::new();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let TypeElement::Entier = element_pile.type_element() {
|
||||||
|
texte += &nombre::affiche_nombre(pile.clone(), variables)?;
|
||||||
|
pile = Vec::new();
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn calcul_texte() {
|
||||||
|
let pendragon = Pendragon::nouveau();
|
||||||
|
let a = 2345678;
|
||||||
|
let b = 987654;
|
||||||
|
|
||||||
|
let possible_expression = pendragon.elements_texte(&format!("\"hello\" puis {} fois {} puis \"there\" puis vrai ou faux puis trois puis deux puis alinéa puis retour à la ligne",
|
||||||
|
nombre::nombre_comme_texte(a),
|
||||||
|
nombre::nombre_comme_texte(b)));
|
||||||
|
match possible_expression {
|
||||||
|
Ok(expression) => {
|
||||||
|
match calcule_texte(expression, &HashMap::new()) {
|
||||||
|
Ok(texte) => {
|
||||||
|
let vrai_texte = format!("hello{}therevraitroisdeux\t\n", nombre::nombre_comme_texte(a*b));
|
||||||
|
assert_eq!(texte, vrai_texte, "Calcul d'expression (texte) donne un mauvais résultat : {}", texte);
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Calcul d'expression (texte) échoué, avec l'erreur : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Détermination d'expression (texte) échouée : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn conversion_texte() {
|
||||||
|
let pendragon = Pendragon::nouveau();
|
||||||
|
let texte = "\"hello aaaa puis AERTY et ou fois six\"";
|
||||||
|
match pendragon.elements_texte(texte) {
|
||||||
|
Ok(expression) => {
|
||||||
|
if expression.len() != 2 {
|
||||||
|
panic!("L'expression (texte) devrait contenir deux éléments (texte et puis), contient : {:?}", expression);
|
||||||
|
}
|
||||||
|
assert_eq!(expression[0], Element::Texte(texte[1..texte.len()-1].into()), "Calcul d'expression (texte) donne un mauvais résultat : {}", texte);
|
||||||
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
panic!("Conversion échouée (texte) : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn erreur_conversion_texte() {
|
||||||
|
let pendragon = Pendragon::nouveau();
|
||||||
|
let textes = vec![
|
||||||
|
"trois puis puis un",
|
||||||
|
"\" test",
|
||||||
|
"puis",
|
||||||
|
"un puis",
|
||||||
|
"puis un",
|
||||||
|
];
|
||||||
|
for texte in textes {
|
||||||
|
let Err(raison) = pendragon.elements_texte(texte) else {
|
||||||
|
panic!("Ne devrait pas réussir à convertir le texte '{}'", texte);
|
||||||
|
};
|
||||||
|
let ErreurPendragon::TexteInvalide(_) = raison else {
|
||||||
|
panic!("Erreur imprévue pour convertir le texte '{}' : {}", texte, raison);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
src/pendragon/vocabulaire.rs
Normal file
54
src/pendragon/vocabulaire.rs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
|
||||||
|
pub enum MotCle {
|
||||||
|
Definis,
|
||||||
|
Modifie,
|
||||||
|
Affiche,
|
||||||
|
Demande,
|
||||||
|
Si,
|
||||||
|
Sinon,
|
||||||
|
NotaBene,
|
||||||
|
Plus,
|
||||||
|
Moins,
|
||||||
|
Fois,
|
||||||
|
Divise,
|
||||||
|
Et,
|
||||||
|
Ou,
|
||||||
|
Non,
|
||||||
|
OuvreParenthese,
|
||||||
|
FermeParenthese,
|
||||||
|
Puis,
|
||||||
|
Alinea,
|
||||||
|
RetourLigne,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub impl MotCle {
|
||||||
|
fn comme_texte(&self) -> String {
|
||||||
|
match Self {
|
||||||
|
Self::Definis,
|
||||||
|
Self::Modifie,
|
||||||
|
Self::Affiche,
|
||||||
|
Self::Demande,
|
||||||
|
Self::Si,
|
||||||
|
Self::Sinon,
|
||||||
|
Self::NotaBene,
|
||||||
|
Plus,
|
||||||
|
Moins,
|
||||||
|
Fois,
|
||||||
|
Divise,
|
||||||
|
Et,
|
||||||
|
Ou,
|
||||||
|
Non,
|
||||||
|
OuvreParenthese,
|
||||||
|
FermeParenthese,
|
||||||
|
Puis,
|
||||||
|
Alinea,
|
||||||
|
RetourLigne,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn depuis_texte(texte: &str) -> Self {
|
||||||
|
match texte {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,68 +0,0 @@
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn affiche_booleen(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<String, ErreurPendragon> {
|
|
||||||
let booleen = calcule_booleen(expression.clone(), variables)?;
|
|
||||||
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 {
|
|
||||||
return Err(ErreurPendragon::MauvaisType(nom.into(), variable.type_element().nom(), "booleen".into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Element::Comparaison(comparaison) = element {
|
|
||||||
pile.push(comparaison.calcule(variables)?);
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
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("il reste plusieurs éléments dans la pile".into()))
|
|
||||||
}
|
|
||||||
Ok(pile[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn booleen_comme_texte(booleen: bool) -> String {
|
|
||||||
if booleen {
|
|
||||||
"vrai".into()
|
|
||||||
} else {
|
|
||||||
"faux".into()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
use std::io;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use crate::pendragon::structure::*;
|
|
||||||
use crate::display::ErreurPendragon;
|
|
||||||
|
|
||||||
pub mod booleen;
|
|
||||||
pub mod texte;
|
|
||||||
pub mod nombre;
|
|
||||||
|
|
||||||
impl Programme {
|
|
||||||
pub fn execute(&self) -> Result<(), ErreurPendragon> {
|
|
||||||
let mut variables_globales: HashMap<String, Element> = HashMap::new();
|
|
||||||
for phrase in &self.contenu {
|
|
||||||
match phrase {
|
|
||||||
Phrase::Commande(commande) => commande.execute(&mut variables_globales)?,
|
|
||||||
Phrase::Bloc(bloc) => bloc.execute(&mut variables_globales)?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bloc {
|
|
||||||
pub fn execute(&self, variables: &mut HashMap<String, Element>) -> Result<(), ErreurPendragon> {
|
|
||||||
if booleen::calcule_booleen(self.condition.clone(), variables)? {
|
|
||||||
for phrase in &self.contenu {
|
|
||||||
match phrase {
|
|
||||||
Phrase::Commande(commande) => commande.execute(variables)?,
|
|
||||||
Phrase::Bloc(bloc) => bloc.execute(variables)?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while booleen::calcule_booleen(self.condition.clone(), variables)? && self.repete {
|
|
||||||
for phrase in &self.contenu {
|
|
||||||
match phrase {
|
|
||||||
Phrase::Commande(commande) => commande.execute(variables)?,
|
|
||||||
Phrase::Bloc(bloc) => bloc.execute(variables)?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} //else if self.contenu_sinon.len() > 0 {
|
|
||||||
// for phrase in &self.contenu_sinon {
|
|
||||||
// match phrase {
|
|
||||||
// Phrase::Commande(commande) => commande.execute(variables)?,
|
|
||||||
// Phrase::Bloc(bloc) => bloc.execute(variables)?,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Commande {
|
|
||||||
fn execute(&self, variables: &mut HashMap<String, Element>) -> Result<(), ErreurPendragon> {
|
|
||||||
match self {
|
|
||||||
Commande::Definis(nom, type_element) => {
|
|
||||||
variables.insert(nom.to_string(), type_element.comme_element());
|
|
||||||
}
|
|
||||||
Commande::Demande(nom) => {
|
|
||||||
let valeur = variables[nom].type_element().demande_valeur(&nom)?;
|
|
||||||
variables.insert(nom.to_string(), valeur);
|
|
||||||
}
|
|
||||||
Commande::Modifie(nom, expression) => {
|
|
||||||
let valeur = match variables[nom].type_element() {
|
|
||||||
TypeElement::Entier => Element::Entier(nombre::calcule_nombre(expression.clone(), variables)?),
|
|
||||||
TypeElement::Texte => Element::Texte(texte::calcule_texte(expression.clone(), variables)?),
|
|
||||||
TypeElement::Booleen => Element::Booleen(booleen::calcule_booleen(expression.clone(), variables)?),
|
|
||||||
};
|
|
||||||
variables.insert(nom.to_string(), valeur);
|
|
||||||
}
|
|
||||||
Commande::Affiche(expression) => {
|
|
||||||
println!("{}", texte::calcule_texte(expression.to_vec(), variables)?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeElement {
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Element {
|
|
||||||
pub fn compare(&self, element: Element, comparaison: TypeComparaison) -> Result<bool, ErreurPendragon> {
|
|
||||||
if let TypeComparaison::Egal = comparaison {
|
|
||||||
return Ok(*self == element)
|
|
||||||
}
|
|
||||||
if let TypeComparaison::Different = comparaison {
|
|
||||||
return Ok(*self != element)
|
|
||||||
}
|
|
||||||
let Self::Entier(nombre_a) = self else {
|
|
||||||
return Err(ErreurPendragon::ComparaisonInvalide(format!("comparaison numérique avec {}", self)))
|
|
||||||
};
|
|
||||||
let Self::Entier(nombre_b) = element else {
|
|
||||||
return Err(ErreurPendragon::ComparaisonInvalide(format!("comparaison numérique avec {}", element)))
|
|
||||||
};
|
|
||||||
match comparaison {
|
|
||||||
TypeComparaison::SuperieurEgal => Ok(*nombre_a >= nombre_b),
|
|
||||||
TypeComparaison::InferieurEgal => Ok(*nombre_a <= nombre_b),
|
|
||||||
TypeComparaison::Superieur => Ok(*nombre_a > nombre_b),
|
|
||||||
TypeComparaison::Inferieur => Ok(*nombre_a < nombre_b),
|
|
||||||
_ => Err(ErreurPendragon::ComparaisonInvalide("problème de logique".into())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Comparaison {
|
|
||||||
pub fn calcule(&self, variables: &HashMap<String, Element>) -> Result<bool, ErreurPendragon> {
|
|
||||||
let Some(ref comparaison) = self.type_comparaison else {
|
|
||||||
return Err(ErreurPendragon::ComparaisonInvalide("la comparaison n'a pas de type".into()))
|
|
||||||
};
|
|
||||||
let Some(element) = self.membre_a.first() else {
|
|
||||||
return Err(ErreurPendragon::ComparaisonInvalide("il n'y a pas de premier membre".into()))
|
|
||||||
};
|
|
||||||
let (membre_a, membre_b) = match element.type_element() {
|
|
||||||
TypeElement::Entier => {
|
|
||||||
let membre_a = Element::Entier(nombre::calcule_nombre(self.membre_a.clone(), variables)?);
|
|
||||||
let membre_b = Element::Entier(nombre::calcule_nombre(self.membre_b.clone(), variables)?);
|
|
||||||
(membre_a, membre_b)
|
|
||||||
}
|
|
||||||
TypeElement::Texte => {
|
|
||||||
let membre_a = Element::Texte(texte::calcule_texte(self.membre_a.clone(), variables)?);
|
|
||||||
let membre_b = Element::Texte(texte::calcule_texte(self.membre_b.clone(), variables)?);
|
|
||||||
(membre_a, membre_b)
|
|
||||||
}
|
|
||||||
TypeElement::Booleen => {
|
|
||||||
let membre_a = Element::Booleen(booleen::calcule_booleen(self.membre_a.clone(), variables)?);
|
|
||||||
let membre_b = Element::Booleen(booleen::calcule_booleen(self.membre_b.clone(), variables)?);
|
|
||||||
(membre_a, membre_b)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(membre_a.compare(membre_b, comparaison.clone())?)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
use crate::nombre::*;
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn affiche_nombre(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<String, ErreurPendragon> {
|
|
||||||
let nombre = calcule_nombre(expression.clone(), variables)?;
|
|
||||||
Ok(nombre_comme_texte(nombre))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn calcule_nombre(expression: Vec<Element>, variables: &HashMap<String, Element>) -> Result<usize, ErreurPendragon> {
|
|
||||||
let mut pile: Vec<usize> = Vec::new();
|
|
||||||
|
|
||||||
for element in expression {
|
|
||||||
if let Element::Entier(nombre) = element {
|
|
||||||
pile.push(nombre);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Element::Variable(nom, _) = element {
|
|
||||||
let Some(variable) = variables.get(&nom) else {
|
|
||||||
return Err(ErreurPendragon::VariableInconnue(nom.into()))
|
|
||||||
};
|
|
||||||
if let Element::Entier(nombre) = variable {
|
|
||||||
pile.push(*nombre);
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
return Err(ErreurPendragon::MauvaisType(nom.into(), variable.type_element().nom(), "entier".into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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_a);
|
|
||||||
}
|
|
||||||
Operateur::Moins => {
|
|
||||||
if nombre_b < nombre_a {
|
|
||||||
return Err(ErreurPendragon::CalculEntier(format!("a essayé de soustraire '{}' à '{}'", nombre_comme_texte(nombre_a), nombre_comme_texte(nombre_b))))
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
if nombre == 0 {
|
|
||||||
return "zéro".to_string()
|
|
||||||
}
|
|
||||||
if nombre >= 10usize.pow(18) {
|
|
||||||
return "infini".to_string()
|
|
||||||
}
|
|
||||||
let mut groupes: Vec<usize> = vec![];
|
|
||||||
let mut nombre = nombre;
|
|
||||||
while nombre > 0 {
|
|
||||||
groupes.insert(0, nombre % 1000);
|
|
||||||
nombre /= 1000;
|
|
||||||
}
|
|
||||||
let mut chaine: String = "".to_string();
|
|
||||||
|
|
||||||
for index in 0..groupes.len() {
|
|
||||||
if groupes[index] == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
let pluriel: &str = if (groupes.len() - index - 1 > 1) && groupes[index] > 1 {
|
|
||||||
"s"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
if index < groupes.len() - 1 {
|
|
||||||
let union = if index > 0 {UNION} else {""};
|
|
||||||
let chiffre = if groupes.len() - index - 1 == 1 && groupes[index] == 1 { // un mille
|
|
||||||
"".to_string()
|
|
||||||
} else {
|
|
||||||
petit_nombre_comme_texte(groupes[index]) + UNION
|
|
||||||
};
|
|
||||||
chaine += &format!("{}{}{}{}",
|
|
||||||
union,
|
|
||||||
chiffre,
|
|
||||||
NOMS_SEPARATEURS[groupes.len() - index - 1],
|
|
||||||
pluriel,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let union = if index > 0 {UNION} else {""};
|
|
||||||
chaine += union;
|
|
||||||
chaine += &petit_nombre_comme_texte(groupes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
chaine
|
|
||||||
}
|
|
||||||
|
|
||||||
fn petit_nombre_comme_texte(nombre: usize) -> String {
|
|
||||||
let nombre = nombre.clamp(0, 999);
|
|
||||||
let centaine = nombre / 100;
|
|
||||||
let dizaine = (nombre % 100) / 10;
|
|
||||||
let unité = nombre % 10;
|
|
||||||
|
|
||||||
let centaine_texte = if centaine > 1 {
|
|
||||||
format!("{}{}cent", NOMS_UNITES[centaine], UNION)
|
|
||||||
} else if centaine > 0 {
|
|
||||||
"cent".to_string()
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let décalage_dizaine = if [1, 7, 9].contains(&dizaine) {1} else {0};
|
|
||||||
let dizaine_texte = NOMS_DIZAINES[dizaine - décalage_dizaine];
|
|
||||||
let séparation = if unité == 1 && ![0, 1, 8, 9].contains(&dizaine) {UNION.to_string() + "et"} else {"".to_string()};
|
|
||||||
let unité_texte = if [1, 7, 9].contains(&dizaine) {NOMS_UNITES_DIX[unité]} else {NOMS_UNITES[unité]};
|
|
||||||
|
|
||||||
let mut texte_nombre = format!("{}{}{}{}{}{}", centaine_texte, UNION, dizaine_texte, séparation, UNION, unité_texte);
|
|
||||||
|
|
||||||
while texte_nombre.contains("--") {
|
|
||||||
texte_nombre = texte_nombre.replace("--","-");
|
|
||||||
}
|
|
||||||
if texte_nombre.starts_with("-") {
|
|
||||||
texte_nombre = texte_nombre[1..texte_nombre.len()].to_string();
|
|
||||||
}
|
|
||||||
if texte_nombre.ends_with("-") {
|
|
||||||
texte_nombre = texte_nombre[0..texte_nombre.len()-1].to_string();
|
|
||||||
}
|
|
||||||
texte_nombre
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
use super::*;
|
|
||||||
|
|
||||||
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::Puis = 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)?;
|
|
||||||
pile = Vec::new();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let TypeElement::Entier = element_pile.type_element() {
|
|
||||||
texte += &nombre::affiche_nombre(pile.clone(), variables)?;
|
|
||||||
pile = Vec::new();
|
|
||||||
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)
|
|
||||||
}
|
|
26
test.dr
26
test.dr
|
@ -1,17 +1,19 @@
|
||||||
Définis A comme entier. Définis B comme entier.
|
Définis A comme entier. Définis F comme texte.
|
||||||
Modifie B avec un.
|
Définis B comme entier.
|
||||||
|
Définis C comme entier.
|
||||||
|
Nota Bene : A est la variable pour un polynôme.
|
||||||
|
|
||||||
Définis N comme entier.
|
Modifie A avec dix-sept plus trois.
|
||||||
Modifie N avec trente.
|
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).
|
||||||
|
|
||||||
Tant que N est supérieur à zéro,
|
Affiche "Résultat : " puis B.
|
||||||
Modifie N avec N moins un.
|
|
||||||
|
|
||||||
Affiche A.
|
Si A supérieur ou égal à trois,
|
||||||
Affiche B.
|
|
||||||
Modifie A avec A plus B.
|
|
||||||
Modifie B avec A plus B.
|
|
||||||
|
|
||||||
Affiche "Fin".
|
Définis Bool comme booléen.
|
||||||
|
Modifie Bool avec vrai.
|
||||||
|
Affiche vrai et faux.
|
||||||
|
|
||||||
Nota Bene : Ceci est un programme qui affiche deux fois N nombres de la suite de Fibonacci.
|
Affiche alinéa puis trois plus un puis retour à la ligne puis "test".
|
Loading…
Reference in a new issue