megamorse_proc_macro/
lib.rs

1//! This crate contains the procedural macro that is used to convert a string of morse code into a
2//! sequence of MorseWords.
3//!
4//! # Examples
5//!
6//! ```
7//! let words = morse!(... ___ ...);
8//!
9//! for word in words.into_iter() {
10//!    player.play_word(word).unwrap();
11//! }
12//! ```
13extern crate proc_macro;
14use proc_macro::TokenStream;
15
16macro_rules! err {
17    ($e:expr) => {{
18        let err = format!("compile_error!(\"{}\")", $e);
19
20        return err.parse().unwrap();
21    }};
22}
23
24#[proc_macro]
25pub fn morse(item: TokenStream) -> TokenStream {
26    let as_string = item.to_string();
27    let mut parsed_words: Vec<String> = Vec::new();
28
29    let words = as_string.split_whitespace();
30
31    for word in words {
32        if word.len() > 5 {
33            err!(format!(
34                "Word is too long: '{}'.\nMaximum length is 5, actual length is {}",
35                word,
36                word.len()
37            ));
38        }
39
40        let mut codes: Vec<&str> = Vec::with_capacity(as_string.len());
41
42        for c in word.chars() {
43            match c {
44                ' ' => {}
45                '.' => codes.push("megamorse::MorseCode::Dot"),
46                '-' => codes.push("megamorse::MorseCode::Dash"),
47                '_' => codes.push("megamorse::MorseCode::Dash"),
48                _ => err!(format!("Invalid character in morse code: {}", c)),
49            }
50        }
51        let joined = codes.join(", ");
52        let full = format!("megamorse::MorseWord::from([{}])", joined);
53
54        parsed_words.push(full);
55    }
56
57    let joined = parsed_words.join(", ");
58    let out_string = format!("[{}]", joined);
59
60    out_string.parse().unwrap()
61}