/// Look ahead one character in the input /// /// May need to look ahead one character in the input string to determine the /// proper rune. For instance `&`, vs `&&`. #[macro_export] macro_rules! next { ($chars:expr, $i:expr, $otherwise:expr, $rune:expr, $ahead:expr) => { match $chars.clone().peekable().peek() { Some(c) if *c == $ahead => { $chars.next(); $i += 1; $rune } Some(_) => $otherwise, None => $otherwise, } }; } /// Keep pushing to the [Word][super::super::elements::word::Word] stack /// /// If a [Rune::String][super::super::elements::rune::Rune] character is found, /// stop interpreting special characters, and push all characters to the /// [Word][super::super::elements::word::Word] stack, until the corresponding /// [Rune::String][super::super::elements::rune::Rune] character is found. #[macro_export] macro_rules! string { ($chars:expr, $j:expr, $i:expr, $c:expr, $word:expr) => { let token = $c; loop { match $chars.next() { None => return Err(Mishap::PartialMishap($j, $i, $c)), Some(c) if c == token => break, Some(c) if token == '\'' && c == '$' => { $word.push('\x0e'); $i += 1; } Some(c) => { $word.push(c); $i += 1; } } } continue; }; } /// Same as [string!] macro, but look for newline or EOF #[macro_export] macro_rules! remark { ($chars:expr) => { loop { match $chars.next() { None => break, Some(c) if c == '\n' => break, Some(_) => {} } } continue; }; } /// Same as the [string!] macro, but don't `continue` #[macro_export] macro_rules! poem { ($chars:expr, $j:expr, $i:expr, $c:expr, $verse:expr, $word:expr, $env:expr) => { let token = $c; let mut poetry = Word::new(); loop { match $chars.next() { None => return Err(Mishap::PartialMishap($j, $i, $c)), Some(c) if c == token => break, Some(c) => { poetry.push(c); $i += 1; } } } let sp = Poem::read(poetry.iter().collect(), $env); let sp = match sp { Ok(sp) => sp, Err(e) => return Err(e), }; $verse.poems.push(sp); $word.push('\x0b'); }; } /// Append a verse to the poem /// /// Append a verse to poem, first checking for aliases in the environment, and /// processing the alias first, if necessary. #[macro_export] macro_rules! append { ($poem:expr, $last:expr, $meter:expr, $verse:expr, $env:expr) => { if !$verse.is_empty() { match $env.aliases.get(&$verse.verb()) { Some(alias) => { let alias = alias.to_string(); let mut poem = Poem::read(alias, $env)?; let len = poem.len(); for (i, verse) in poem.iter_mut().enumerate() { if $verse.clause().is_some() && i + 1 == len { verse.stanza.append(&mut $verse.clause().unwrap()); } $poem.push(verse.clone()); } } None => { $poem.add(&mut $verse, $last, $meter); } } } }; }