politeness_macro_impl/
lib.rs1#![feature(proc_macro_hygiene)]
2#![feature(proc_macro_span)]
3#![feature(extend_one)]
4
5use proc_macro::*;
6use proc_macro::TokenTree::Ident;
7
8enum PolitenessResult {
9 Correct,
10 TooPolite,
11 TooRude
12}
13
14fn count_tokens(strm: TokenStream) -> (i32, i32) {
15 let mut total = 0;
16 let mut polite = 0;
17 let mut input = strm.clone().into_iter();
18 while let Some(t) = input.next() {
19 match t {
20 TokenTree::Group(x) => {
21 let l = count_tokens(x.stream());
22 total += l.0;
23 polite += l.1;
24 },
25 Ident(x) if x.to_string() == "please" => {
26 polite += 1;
27 total += 1;
28 },
29 _ => {
30 total += 1;
31 }
32 }
33 }
34 (total, polite)
35}
36
37fn polite_enough(total: i32, polite: i32) -> (PolitenessResult, f32) {
38 let ratio = if polite == 0 {
39 0.0
40 } else {
41 polite as f32 / total as f32
42 };
43
44 if ratio >= 0.0 && ratio <= 0.15 {
46 (PolitenessResult::TooRude, ratio)
47 } else if ratio >= 0.15 && ratio <= 0.4 {
48 (PolitenessResult::Correct, ratio)
49 } else if ratio >= 0.4 {
50 (PolitenessResult::TooPolite, ratio)
51 } else {
52 panic!("what")
53 }
54}
55
56fn remove_please_from_group(grp: Group) -> Group {
57 let strm = remove_please(grp.stream());
58 Group::new(grp.delimiter(), strm)
59}
60
61fn remove_please(tk: TokenStream) -> TokenStream {
62 let mut k = tk.clone().into_iter();
63 let mut new = TokenStream::new();
64 while let Some(f) = k.next() {
65 match f {
66 TokenTree::Group(x) => {
67 new.extend_one(TokenTree::Group(remove_please_from_group(x)));
68 },
69 Ident(x) if x.to_string() == "please" => {
70 },
72 x @ _ => {
73 new.extend_one(x);
74 }
75 }
76 };
77 new
78}
79
80#[proc_macro]
81pub fn polite(tk: TokenStream) -> TokenStream {
82 let howpolite = count_tokens(tk.clone());
83 match polite_enough(howpolite.0, howpolite.1) {
84 (PolitenessResult::Correct, _) => {},
85 (PolitenessResult::TooRude, x) => {
86 panic!("code was too rude (value {x})")
87 },
88 (PolitenessResult::TooPolite, x) => {
89 panic!("code was too polite (value {x})")
90 }
91 }
92
93 let new = remove_please(tk);
94 new
95}