notation_dsl/fretted/
fretboard.rs1use fehler::throws;
2use notation_proto::prelude::{
3 Fretboard4, Fretboard6, FrettedEntry4, FrettedEntry6, GuitarTuning,
4 GUITAR_FRET_NUM_ACOUSTIC, Pitch, Octave,
5};
6use notation_proto::proto_entry::ProtoEntry;
7use proc_macro2::TokenStream;
8use quote::{quote, ToTokens};
9use syn::parse::{Error, Parse, ParseStream};
10use syn::{Ident, LitInt, Token};
11
12use crate::context::Context;
13
14pub struct FretboardDsl {
15 pub tuning: Option<Ident>,
16 pub fret_num: Option<usize>,
17 pub capo: Option<u8>,
18}
19
20mod kw {
21 syn::custom_keyword!(tuning);
22 syn::custom_keyword!(fret_num);
23 syn::custom_keyword!(capo);
24}
25
26impl Parse for FretboardDsl {
27 #[throws(Error)]
28 fn parse(input: ParseStream) -> Self {
29 let mut fret_num = None;
30 let mut tuning = None;
31 let mut capo = None;
32 loop {
33 if input.peek(kw::tuning) {
34 input.parse::<kw::tuning>()?;
35 input.parse::<Token![:]>()?;
36 tuning = Some(input.parse::<Ident>()?);
37 } else if input.peek(kw::fret_num) {
38 input.parse::<kw::fret_num>()?;
39 input.parse::<Token![:]>()?;
40 fret_num = Some(input.parse::<LitInt>()?.base10_parse::<usize>()?);
41 } else if input.peek(kw::capo) {
42 input.parse::<kw::capo>()?;
43 input.parse::<Token![:]>()?;
44 capo = Some(input.parse::<LitInt>()?.base10_parse::<u8>()?);
45 } else {
46 break;
47 }
48 }
49 FretboardDsl {
50 tuning,
51 fret_num,
52 capo,
53 }
54 }
55}
56
57impl ToTokens for FretboardDsl {
58 fn to_tokens(&self, tokens: &mut TokenStream) {
59 let FretboardDsl {
60 tuning,
61 fret_num,
62 capo,
63 } = self;
64 let string_num = Context::fretted().string_num;
65 let fret_num = fret_num.unwrap_or(match string_num {
66 6 => GUITAR_FRET_NUM_ACOUSTIC,
67 _ => GUITAR_FRET_NUM_ACOUSTIC,
68 });
69 let capo = capo.unwrap_or(0);
70 let tuning_quote = match tuning {
71 Some(tuning) => {
72 let tuning_quote = tuning.to_string();
73 match string_num {
74 _ => quote! { GuitarTuning::from_ident(#tuning_quote)},
75 }
76 }
77 None => match string_num {
78 _ => quote! { GuitarTuning::Standard },
79 },
80 };
81 let fretted_entry_quote = Context::fretted().fretted_entry_quote();
82 let fretboard_quote = Context::fretted().fretboard_quote();
83 tokens.extend(quote! {
84 ProtoEntry::from(#fretted_entry_quote::from(
85 #fretboard_quote::new(#fret_num, #tuning_quote.into(), #capo)
86 ))
87 });
88 }
89}
90
91impl FretboardDsl {
92 pub fn to_proto(&self) -> ProtoEntry {
93 let FretboardDsl {
94 tuning,
95 fret_num,
96 capo,
97 } = self;
98 let string_num = Context::fretted().string_num;
99 let fret_num = fret_num.unwrap_or(match string_num {
100 6 => GUITAR_FRET_NUM_ACOUSTIC,
101 _ => GUITAR_FRET_NUM_ACOUSTIC,
102 });
103 let capo = capo.unwrap_or(0);
104 match string_num {
105 4 => {
106 let tuning = [(Pitch::E, Octave::P2).into(); 4]; ProtoEntry::from(FrettedEntry4::from(Fretboard4::new(fret_num, tuning, capo)))
108 }
109 _ => {
110 let tuning = match tuning {
111 Some(ident) => GuitarTuning::from_ident(ident.to_string().as_str()),
112 None => GuitarTuning::Standard,
113 };
114 ProtoEntry::from(FrettedEntry6::from(Fretboard6::new(
115 fret_num,
116 tuning.into(),
117 capo,
118 )))
119 }
120 }
121 }
122}