diff options
author | Rory Dudley | 2024-03-05 00:42:28 -0700 |
---|---|---|
committer | Rory Dudley | 2024-03-05 00:42:28 -0700 |
commit | 37e1ae98dc9309715e9415962f21484a807d2c56 (patch) | |
tree | 69444755d1a0095f5a7cfad66ab966f83f46d4aa /src/recite.rs | |
parent | e03ceec834aeca1f383b19354e32987bc2d59506 (diff) | |
download | dwarvish-37e1ae98dc9309715e9415962f21484a807d2c56.tar.gz |
Poem::read macros
Added the following macros:
push!: Creates a Verse from a stanza, taking into account some extra
options (such as the Meter).
push1!: Creates a Verse from a stanza, but also allows looking ahead
by a single character, in order to pattern match certain meters (i.e.
And ('&&') and Addendum ('>>')).
Replaced the code in the huge, redundant match statements in Poem::read
with the macros described above.
Diffstat (limited to 'src/recite.rs')
-rw-r--r-- | src/recite.rs | 288 |
1 files changed, 54 insertions, 234 deletions
diff --git a/src/recite.rs b/src/recite.rs index 05e49f3..07e6276 100644 --- a/src/recite.rs +++ b/src/recite.rs @@ -1,6 +1,7 @@ +mod parse; pub mod path; mod ps; -use crate::{btask, ctask, task}; +use crate::{btask, ctask, push, push1, task}; use core::fmt; use libc::{waitpid, WNOHANG}; use path::prefresh; @@ -695,232 +696,71 @@ impl Poem { // The character represents the Couplet Meter Some(meter) if meter == '|' => { - // If there are chars on the word stack, push that word - // onto the stanza - if !word.is_empty() { - stanza.push(word.iter().collect()); - } - - // A meter indicates the end of a verse - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::Couplet, + push!( + word, + stanza, Verse::couplet(prev), - Verse::rw(prev), - )); - - // Clear the stacks - stanza.clear(); - word.clear(); + prev, + verses, + Meter::Couplet + ); } // The character represents the Quiet (or And) Meter Some(meter) if meter == '&' => { - // If there are chars on the word stack, push that word - // onto the stanza - if !word.is_empty() { - stanza.push(word.iter().collect()); - } - - // Need to peek at the next character, since '&' can mean - // Meter::Quiet, or '&&' can mean Meter::And - match chars.clone().peekable().peek() { - // Indicated Meter::And - Some(c) if c == &'&' => { - // Pop the next character from the input string - // (since we know what it is) - chars.next(); - - // A meter indicates the end of a verse - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::And, - Verse::couplet(prev), - Verse::rw(prev), - )); - } - - // Indicates Meter::Quiet - Some(_) => { - // A meter indicates the end of a verse - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::Quiet, - Verse::couplet(prev), - Verse::rw(prev), - )); - } - - // Indicated the end of the input - None => { - // The end of input also indicates the end of a - // verse - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::Quiet, - Verse::couplet(prev), - Verse::rw(prev), - )); - - // We can break out of the loop here, since it's - // the end of the raw input - break; - } - } - - // Clear the stacks - stanza.clear(); - word.clear(); + push1!( + word, + stanza, + chars, + prev, + verses, + Meter::Quiet, + '&', + Meter::And + ); } // The character represents the String Meter Some(meter) if meter == ';' => { - // If there are chars on the word stack, push that word - // onto the stanza - if !word.is_empty() { - stanza.push(word.iter().collect()); - } - - // Check if the last verse was a meter of Read, Write, or - // Addendum, and throw an error if it is - if Verse::rw(prev) && stanza.is_empty() { - let rw = match prev.unwrap().meter { - Meter::Read => "read", - Meter::Write => "write", - Meter::Addendum => "append", - _ => "", - }; - eprintln!("dwvsh: parse error: no {} file(s) specified", rw); - return None; - } - - // A meter indicates the end of a verse - if !stanza.is_empty() { - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::String, - Verse::couplet(prev), - Verse::rw(prev), - )); - } - - // Clear the stacks - stanza.clear(); - word.clear(); + push!( + word, + stanza, + Verse::couplet(prev), + prev, + verses, + Meter::String + ); } // The character represents the Read Meter Some(meter) if meter == '<' => { - // If there are chars on the word stack, push that word - // onto the stanza - if !word.is_empty() { - stanza.push(word.iter().collect()); - } - - // A meter indicates the end of a verse - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::Read, - true, - Verse::rw(prev), - )); - - // Clear the stacks - stanza.clear(); - word.clear(); + push!(word, stanza, true, prev, verses, Meter::Read); } // The character represents the Write Meter Some(meter) if meter == '>' => { - // If there are chars on the word stack, push that word - // onto the stanza - if !word.is_empty() { - stanza.push(word.iter().collect()); - } - - // Check if the last verse was a meter of Read, Write, or - // Addendum, and throw an error if it is - if Verse::rw(prev) && stanza.is_empty() { - let rw = match prev.unwrap().meter { - Meter::Read => "read", - Meter::Write => "write", - Meter::Addendum => "append", - _ => "", - }; - eprintln!("dwvsh: parse error: no {} file(s) specified", rw); - return None; - } - - // Need to peek at the next character, since '>' can mean - // Meter::Write, or '>>' can mean Meter::Addendum - match chars.clone().peekable().peek() { - // Indicated Meter::Addendum - Some(c) if c == &'>' => { - // Pop the next character from the input string - // (since we know what it is) - chars.next(); - - // A meter indicates the end of a verse - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::Addendum, - Verse::couplet(prev), - Verse::rw(prev), - )); - } - - // Indicates Meter::Write - Some(_) => { - // A meter indicates the end of a verse - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::Write, - Verse::couplet(prev), - Verse::rw(prev), - )); - } - - // Indicated the end of the input - None => { - // A meter indicates the end of a verse - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::Write, - Verse::couplet(prev), - Verse::rw(prev), - )); - - // We can break out of the loop here, since it's - // the end of the raw input - } - } - - // Clear the stacks - stanza.clear(); - word.clear(); + push1!( + word, + stanza, + chars, + prev, + verses, + Meter::Write, + '>', + Meter::Addendum + ); } // The character is a newline (may happen if parsing from a file) Some(char) if char == '\n' => { - // If there are chars on the word stack, push that word - // onto the stanza - if !word.is_empty() { - stanza.push(word.iter().collect()); - } - - // A newline indicates the end of a verse - if !stanza.is_empty() { - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::String, - Verse::couplet(prev), - Verse::rw(prev), - )); - } - - // Clear the stacks - stanza.clear(); - word.clear(); + push!( + word, + stanza, + Verse::couplet(prev), + prev, + verses, + Meter::String + ); } // The character is whitespace @@ -941,34 +781,14 @@ impl Poem { // Indicates the end of the list of characters None => { - // Always push the last word onto the stanza - if !word.is_empty() { - stanza.push(word.iter().collect()); - } - - // Check if the last verse was a meter of Read, Write, or - // Addendum, and throw an error if it is - if Verse::rw(prev) && stanza.is_empty() { - let rw = match prev.unwrap().meter { - Meter::Read => "read", - Meter::Write => "write", - Meter::Addendum => "append", - _ => "", - }; - eprintln!("dwvsh: parse error: no {} file(s) specified", rw); - return None; - } - - // Only push the stanza into a verse if it contains - // any words - if !stanza.is_empty() { - verses.push(Verse::new( - Stanza::new(stanza.clone()), - Meter::None, - Verse::couplet(prev), - Verse::rw(prev), - )); - } + push!( + word, + stanza, + Verse::couplet(prev), + prev, + verses, + Meter::None + ); // Break from the loop, since we are out of chars break; |