commit ff6ac4cf35cc1689de6fb534ddacdae9a391688e Author: Benjamin Bouvier Date: Thu Sep 9 19:40:29 2021 +0200 Commit initial. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0256e97 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +**/*/target +*/target +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..45d1a1f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] +members = [ + "rouille_proc_macro", + "examples" +] diff --git a/README.md b/README.md new file mode 100644 index 0000000..95d96b8 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# rouille + +Aren't you *le tired* from writing Rust programs in English? Do you like saying +"merde" a lot? Would you like to try something different, in an exotic +language? + +**rouille** (French for *Rust*) is here to save the day, and allows one to +write Rust programs in French. See the [examples](./examples/src/main.rs) for +more details about what can be done with it. + +## contributions + +First of all, *merci beaucoup* for considering participating to this joke, the +French government will thank you later! Feel free to throw in a few identifiers +here and there, and open a pull-request against the `principale` (French for +`main`) branch. + +## but why would you do zat + +- horsin around +- making a bit of fun of programming languages using French keywords +- winking at [Marcel](https://github.com/brouberol/marcel) +- playing with raw proc macros +- c'est chic + +## license + +[WTFPL](http://www.wtfpl.net/). diff --git a/examples/Cargo.toml b/examples/Cargo.toml new file mode 100644 index 0000000..ae9a6ba --- /dev/null +++ b/examples/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rouille_examples" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rouille = { path = "../rouille_proc_macro/" } diff --git a/examples/src/main.rs b/examples/src/main.rs new file mode 100644 index 0000000..8769c12 --- /dev/null +++ b/examples/src/main.rs @@ -0,0 +1,69 @@ +rouille::rouille! { + utilisons std::collections::Dictionnaire comme Dico; + + interface CléValeur { + fonction écrire(&soi, clé: Chaine, valeur: Chaine); + fonction lire(&soi, clé: Chaine) -> PeutÊtre<&Chaine>; + } + + statique mutable DICTIONNAIRE: PeutÊtre> = Rien; + + structure Concrète; + + implémentation CléValeur pour Concrète { + fonction écrire(&soi, clé: Chaine, valeur: Chaine) { + soit dico = dangereux { + DICTIONNAIRE.prendre_ou_insérer_avec(Défault::défault) + }; + dico.insérer(clé, valeur); + } + fonction lire(&soi, clé: Chaine) -> PeutÊtre<&Chaine> { + soit dico = dangereux { + DICTIONNAIRE.prendre_ou_insérer_avec(Défault::défault) + }; + dico.lire(&clé) + } + } + + public(cagette) fonction peut_etre(i: u32) -> PeutÊtre> { + si i % 2 == 1 { + si i == 42 { + Quelque(Arf(Chaine::depuis("merde"))) + } sinon { + Quelque(Bien(33)) + } + } sinon { + Rien + } + } + + asynchrone fonction exemple() { + } + + asynchrone fonction exemple2() { + exemple().attend; + } + + fonction principale() { + soit mutable x = 31; + + correspond x { + 42 => { + affiche!("omelette du fromage") + } + _ => affiche!("voila") + } + + pour i de 0..10 { + soit val = boucle { + arrête i; + }; + tant que x < val { + x += 1; + } + x = si soit Quelque(resultat) = peut_etre(i) { + resultat.déballer() + } else { 12 }; + } + } +} diff --git a/rouille_proc_macro/Cargo.toml b/rouille_proc_macro/Cargo.toml new file mode 100644 index 0000000..862a0a6 --- /dev/null +++ b/rouille_proc_macro/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rouille" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[lib] +proc-macro = true diff --git a/rouille_proc_macro/src/lib.rs b/rouille_proc_macro/src/lib.rs new file mode 100644 index 0000000..38809e2 --- /dev/null +++ b/rouille_proc_macro/src/lib.rs @@ -0,0 +1,105 @@ +use proc_macro::{Group, Ident, TokenStream, TokenTree}; + +fn replace_ident(ident: Ident) -> Option { + let ident_str = ident.to_string(); + + let new_str = match ident_str.as_str() { + "Arf" => "Err", + "Bien" => "Ok", + "Chaine" => "String", + "Dictionnaire" => "HashMap", + "Défault" => "Default", + "Erreur" => "Error", + "PeutÊtre" => "Option", + "Quelque" => "Some", + "Rien" => "None", + "Résultat" => "Result", + "Soi" => "Self", + "affiche" => "println", + "arrête" => "break", + "asynchrone" => "async", + "attend" => "await", + "boucle" => "loop", + "bouge" => "move", + "cagette" => "crate", + "comme" => "as", + "constant" => "const", + "correspond" => "match", + "dangereux" => "unsafe", + "de" => "in", + "depuis" => "from", + "dynamique" => "dyn", + "déballer" => "unwrap", + "défault" => "default", + "es" => "io", + "externe" => "extern", + "faux" => "false", + "fonction" => "fn", + "génial" => "super", + "implémentation" => "impl", + "insérer" => "insert", + "interface" => "trait", + "lire" => "get", + "module" => "mod", + "mutable" => "mut", + "nouveau" => "new", + "où" => "where", + "pour" => "for", + "prendre_ou_insérer_avec" => "get_or_insert_with", + "principale" => "main", + "public" => "pub", + "que" => None?, + "renvoie" => "return", + "si" => "if", + "sinon" => "else", + "soi" => "self", + "soit" => "let", + "statique" => "static", + "structure" => "struct", + "suppose" => "expect", + "tant" => "while", + "utilisons" => "use", + "vrai" => "true", + "énumération" => "enum", + + _ => &ident_str, + }; + + let new_ident = Ident::new(new_str, ident.span()); + Some(TokenTree::Ident(new_ident)) +} + +fn replace_tree(tok: TokenTree, out: &mut Vec) { + match tok { + TokenTree::Group(group) => { + let mut group_elem = Vec::new(); + replace_stream(group.stream(), &mut group_elem); + let mut new_stream = TokenStream::new(); + new_stream.extend(group_elem); + out.push(TokenTree::Group(Group::new(group.delimiter(), new_stream))); + } + TokenTree::Ident(ident) => { + if let Some(ident) = replace_ident(ident) { + out.push(ident); + } + } + TokenTree::Punct(..) | TokenTree::Literal(..) => { + out.push(tok); + } + } +} + +fn replace_stream(ts: TokenStream, out: &mut Vec) { + for tok in ts { + replace_tree(tok, out) + } +} + +#[proc_macro] +pub fn rouille(item: TokenStream) -> TokenStream { + let mut returned = Vec::new(); + replace_stream(item, &mut returned); + let mut out = TokenStream::new(); + out.extend(returned); + out +}