Compare commits

..

3 commits

Author SHA1 Message Date
brevalferrari
df342893ee fix rustfmt 2025-06-07 17:38:00 +02:00
brevalferrari
5e38b15f93 more detail for language design 2025-06-07 17:37:33 +02:00
brevalferrari
e45053eebe blip as example for docs.rs example scraping 2025-06-07 17:37:15 +02:00
4 changed files with 48 additions and 17 deletions

View file

@ -47,3 +47,11 @@ raw = ["raw_audio"]
name = "blip" name = "blip"
path = "src/cli/main.rs" path = "src/cli/main.rs"
required-features = ["bin"] required-features = ["bin"]
[[example]]
name = "blip"
path = "src/cli/main.rs"
required-features = ["bin"]
[lints.rust]
missing_docs = "warn"

View file

@ -1,8 +1,8 @@
notes: dorémi abc... as they appear in the note list notes: dorémi abc... as they appear in the note list
variables: $v8 variables: $v8 assign '8' to the variable named 'v'
$v1+2 $v1+2
$vv+1 $vv+1
$v-4.1 as soon as the variable mutation string stops being valid, usual sheet music parsing continues $v-4.1 as soon as the variable mutation string stops being valid, usual sheet music parsing continues (https://en.wikipedia.org/wiki/Maximal_munch)
loops: (...) loops: (...)
(2...) to loop 2 times (2...) to loop 2 times
(n...) to loop n times (taking the integer part with the floor function) (n...) to loop n times (taking the integer part with the floor function)

View file

@ -166,7 +166,7 @@ fn parse_and_compile(opts: &PlayOpts) -> anyhow::Result<Vec<f64>> {
compiler compiler
.compile_all(tokens) .compile_all(tokens)
.inspect(|v| { .inspect(|v| {
let is_nan = |sample| sample.abs().is_nan(); let is_nan = |sample: &f64| sample.abs().is_nan();
if v.iter().all(is_nan) { if v.iter().all(is_nan) {
error!("🎉 All your samples are NaN, you got yourself a \"Not a Song\" (NaS)!") error!("🎉 All your samples are NaN, you got yourself a \"Not a Song\" (NaS)!")
} else if v.iter().any(is_nan) { } else if v.iter().any(is_nan) {

View file

@ -10,10 +10,17 @@ use derive_new::new;
use fasteval::Evaler; use fasteval::Evaler;
use log::{debug, trace, warn}; use log::{debug, trace, warn};
use nom::{ use nom::{
branch::alt, bytes::complete::{tag, take, take_till}, character::{ AsChar, Compare, Input, Parser as _,
branch::alt,
bytes::complete::{tag, take, take_till},
character::{
complete::{char, space1, usize}, complete::{char, space1, usize},
streaming::one_of, streaming::one_of,
}, combinator::{all_consuming, cut, opt, value}, error::{ErrorKind, FromExternalError, ParseError}, multi::many0, sequence::{delimited, preceded}, AsChar, Compare, Input, Parser as _ },
combinator::{all_consuming, cut, opt, value},
error::{ErrorKind, FromExternalError, ParseError},
multi::many0,
sequence::{delimited, preceded},
}; };
use nom_locate::LocatedSpan; use nom_locate::LocatedSpan;
@ -94,7 +101,10 @@ where
impl<I> FromExternalError<I, anyhow::Error> for LocatedVerboseError<I> { impl<I> FromExternalError<I, anyhow::Error> for LocatedVerboseError<I> {
fn from_external_error(input: I, _kind: ErrorKind, e: anyhow::Error) -> Self { fn from_external_error(input: I, _kind: ErrorKind, e: anyhow::Error) -> Self {
Self { location: input, error: Some(e) } Self {
location: input,
error: Some(e),
}
} }
} }
@ -230,6 +240,7 @@ impl Note {
sorted sorted
}; };
move |input: I| { move |input: I| {
#[allow(clippy::type_complexity)]
let mut parsers: Vec<Box<dyn Fn(I) -> IResult<I, Self>>> = notes let mut parsers: Vec<Box<dyn Fn(I) -> IResult<I, Self>>> = notes
.clone() .clone()
.drain(..) .drain(..)
@ -340,7 +351,11 @@ impl Tuplet {
{ {
trace!("making the {} parser", type_name::<Self>()); trace!("making the {} parser", type_name::<Self>());
|input| { |input| {
delimited(char('['), cut(take_till(|c| c == ']').and_then(cut(expect(all_consuming(token_parser(parser)), "input did not match any known grammar for inner tokens (typo?)")))), cut( delimited(char('['),
cut(take_till(|c| c == ']')
.and_then(cut(expect(
all_consuming(token_parser(parser)),
"input did not match any known grammar for inner tokens (typo?)")))), cut(
expect( expect(
char(']'), char(']'),
format!( format!(
@ -405,8 +420,14 @@ impl Slope {
-> IResult<LocatedSpan<&'a str>, VariableChange>, -> IResult<LocatedSpan<&'a str>, VariableChange>,
>, >,
>>() >>()
.as_mut_slice()), format!("expected a slope name from available slope names ({:?})", parser.slopes.clone().into_iter().map(|(s1, _)| s1.as_ref().to_string()).collect::<Vec<_>>()))) .as_mut_slice()),
.and(cut(take_till(|c| c == '}').and_then(cut(expect(all_consuming(token_parser(parser)), "input did not match any known grammar for inner tokens (typo?)"))))), format!(
"expected a slope name from available slope names ({:?})",
parser.slopes.clone().into_iter().map(|(s1, _)| s1.as_ref().to_string()).collect::<Vec<_>>()
)))
.and(cut(take_till(|c| c == '}').and_then(cut(
expect(all_consuming(token_parser(parser)),
"input did not match any known grammar for inner tokens (typo?)"))))),
cut( cut(
expect( expect(
char('}'), char('}'),
@ -520,14 +541,16 @@ mod tests {
VariableChange('n', "1".parse().unwrap()) VariableChange('n', "1".parse().unwrap())
} }
fn parser_generator() -> Parser< type DefaultParser = Parser<
[&'static str; 3], [&'static str; 3],
&'static str, &'static str,
HashMap<String, VariableChange>, HashMap<String, VariableChange>,
String, String,
VariableChange, VariableChange,
[char; 1], [char; 1],
> { >;
fn parser_generator() -> DefaultParser {
Parser::new( Parser::new(
["do", "", "mi"], ["do", "", "mi"],
HashMap::from([ HashMap::from([