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