notation_dsl/fretted/
pick.rs

1use fehler::throws;
2use notation_proto::prelude::{CoreEntry, FrettedEntry4, FrettedEntry6, Pick};
3use notation_proto::proto_entry::ProtoEntry;
4use proc_macro2::TokenStream;
5use quote::{quote, ToTokens};
6use syn::parse::{Error, ParseStream};
7use syn::{LitInt, Token};
8
9use crate::context::Context;
10use crate::core::duration::DurationTweakDsl;
11
12use super::pick_note::PickNoteDsl;
13
14pub struct PickDsl {
15    pub notes: Vec<PickNoteDsl>,
16    pub duration_tweak: Option<DurationTweakDsl>,
17}
18
19impl PickDsl {
20    #[throws(Error)]
21    pub fn parse_without_paren(input: ParseStream, multied: bool, with_paren: bool) -> Self {
22        let mut notes = vec![];
23        if input.peek(Token![_]) {
24            input.parse::<Token![_]>()?;
25        } else {
26            while input.peek(LitInt) {
27                notes.push(input.parse()?);
28                if multied && !with_paren {
29                    break;
30                }
31            }
32        }
33        let duration_tweak = DurationTweakDsl::try_parse(input);
34        PickDsl {
35            notes,
36            duration_tweak,
37        }
38    }
39}
40
41impl ToTokens for PickDsl {
42    fn to_tokens(&self, tokens: &mut TokenStream) {
43        let PickDsl {
44            notes,
45            duration_tweak,
46        } = self;
47        let duration_quote = Context::duration_quote(duration_tweak);
48        if notes.len() == 0 {
49            tokens.extend(quote! {
50                ProtoEntry::from(CoreEntry::from(#duration_quote))
51            });
52        } else {
53            let _string_num = Context::fretted().string_num;
54            let notes_quote: Vec<_> = notes.iter().map(|x| quote! { #x }).collect();
55            let fretted_entry_quote = Context::fretted().fretted_entry_quote();
56            tokens.extend(quote! {
57                ProtoEntry::from(#fretted_entry_quote::from(
58                    (Pick::from(vec![
59                        #(#notes_quote),*
60                    ]), #duration_quote)
61                ))
62            });
63        }
64    }
65}
66
67impl PickDsl {
68    pub fn to_proto(&self) -> ProtoEntry {
69        let PickDsl {
70            notes,
71            duration_tweak,
72        } = self;
73        let duration = Context::tweaked_duration(duration_tweak);
74        if notes.len() == 0 {
75            ProtoEntry::from(CoreEntry::from(duration))
76        } else {
77            let _string_num = Context::fretted().string_num;
78            let notes: Vec<_> = notes.iter().map(|x| x.to_proto()).collect();
79            match Context::fretted().string_num {
80                4 => ProtoEntry::from(FrettedEntry4::from((Pick::from(notes), duration))),
81                _ => ProtoEntry::from(FrettedEntry6::from((Pick::from(notes), duration))),
82            }
83        }
84    }
85}