diff options
author | Rory Dudley | 2024-05-19 18:50:06 -0600 |
---|---|---|
committer | Rory Dudley | 2024-05-19 18:50:06 -0600 |
commit | 4b1b8061e79b42128df4f06fd1e439549bf9696b (patch) | |
tree | 80db43cf7295937751d61435fb4e60118b8a3ea9 /src/poem/read.rs | |
parent | 8756d3e7512c1416cc15a688c62b8f51f030b192 (diff) | |
download | dwarvish-4b1b8061e79b42128df4f06fd1e439549bf9696b.tar.gz |
Handle STDERR, in addition to STDOUT
This patch overhauls the reading and reciting of verses, such that the
redirection of STDERR (in addition to STDOUT, which was already a
feature), is now possible.
Removed the 'stdout' argument from recite(), since it is no longer
needed with how incantations function.
A verse's couplet indicator is now a u8, instead of a bool, with certain
values corresponding to types of couplets, for instance:
ls | grep Ca | lolcat
^ ^ ^
| | 2: right side of a couplet
| 3: both sides of a couplet
1: left side of a couplet
Incantions are no longer hanlded in rune.rs, and the task macros have
been removed. Now, a verse incants itself, matching on its own meter to
determine how to handle the next verse.
The following runes were added to help with handling STDERR:
Write2 -> 2>
WriteAll -> &>
Addendum2 -> 2>>
AddendumAll -> &>>
The 'io' field in verse was changed from an Option<Rune>, to an array of
Runes, since a single verse might have multiple IO operations.
The following fields were added to Verse, to assist with handling
STDERR:
ip -> List of filenames to read into STDIN
op -> List of filenames to send STDOUT to
ep -> List of filenames to send STDERR to
Keep track of channels when reading a poem. Channels are relating to IO
operations. If channel is None, words get pushed to the verse's primary
stanza (i.e. the verb or the clause). If a channel is selected, words
are pushed to one of the aforementioned new fields in Verse.
Read -> ip
Write/Addedum -> op
Write2/Addedum2 -> ep
WriteAll/AddendumAll -> op and ep
Notes
Notes:
This commit also added tests for the new Runes.
Diffstat (limited to 'src/poem/read.rs')
-rw-r--r-- | src/poem/read.rs | 124 |
1 files changed, 90 insertions, 34 deletions
diff --git a/src/poem/read.rs b/src/poem/read.rs index 35ca2e1..da13f76 100644 --- a/src/poem/read.rs +++ b/src/poem/read.rs @@ -42,13 +42,8 @@ impl fmt::Display for Mishap { /// A [Poem] can add more [Verse]s to itself trait Appendable { type Type; - fn add( - &mut self, - verse: &mut Self::Type, - meter: Rune, - last: Rune, - env: &Environment, - ) -> Result<(), Mishap>; + fn add(&mut self, verse: &mut Self::Type, meter: Rune, env: &Environment) + -> Result<(), Mishap>; } impl Appendable for Poem { @@ -61,7 +56,6 @@ impl Appendable for Poem { fn add( &mut self, verse: &mut Self::Type, - last: Rune, meter: Rune, env: &Environment, ) -> Result<(), Mishap> { @@ -69,10 +63,20 @@ impl Appendable for Poem { return Ok(()); } + // Get meter of the last verse + let last = match self.last() { + Some(last) => last.meter, + None => Rune::Else, + }; + // Check the meter verse.meter = meter; - if last == Rune::Couplet || meter == Rune::Couplet { - verse.couplet = true; + if last == Rune::Couplet && meter == Rune::Couplet { + verse.couplet = 3; + } else if last == Rune::Couplet { + verse.couplet = 2; + } else if meter == Rune::Couplet { + verse.couplet = 1; } // Check for aliases @@ -88,10 +92,10 @@ impl Appendable for Poem { }; // The last verse inherits the traits from the original - if verse.couplet { + if verse.couplet > 0 { lv.couplet = verse.couplet; } - lv.io = verse.io; + lv.io = verse.io.clone(); lv.poems = verse.poems.clone(); lv.meter = verse.meter; if verse.clause().is_some() { @@ -147,6 +151,9 @@ impl Readable for Poem { // Keep track of the last rune let mut last = Rune::None; + // Keep track of the channel + let mut channel: Option<Rune> = None; + // Keep track of the line let mut j = 0; @@ -167,7 +174,7 @@ impl Readable for Poem { // If c is none, it indicates the end of a poem, so wrap up and // then break from the loop - verse.add(&mut word); + verse.add(&mut word, channel); // Throw an error if the verse is empty if verse.is_empty() && (last == Rune::Couplet || last == Rune::And) { @@ -175,7 +182,7 @@ impl Readable for Poem { } // Push the verse and break - poem.add(&mut verse, last, Rune::None, env)?; + poem.add(&mut verse, Rune::None, env)?; // append!(poem, last, Rune::None, verse, env); break; } @@ -188,13 +195,31 @@ impl Readable for Poem { '#' => Rune::Remark, '\'' | '"' => Rune::String, '`' => Rune::Poem, - '<' => { - verse.couplet = true; - Rune::Read - } - '>' => next(&mut chars, &mut i, Rune::Write, vec![('>', Rune::Addendum)]), + '<' => Rune::Read, + '>' => next(&mut chars, &mut i, Rune::Write, vec![(">", Rune::Addendum)]), + '1' => next( + &mut chars, + &mut i, + Rune::Else, + vec![(">", Rune::Write), (">>", Rune::Addendum)], + ), + '2' => next( + &mut chars, + &mut i, + Rune::Else, + vec![(">", Rune::Write2), (">>", Rune::Addendum2)], + ), '|' => Rune::Couplet, - '&' => next(&mut chars, &mut i, Rune::Quiet, vec![('&', Rune::And)]), + '&' => next( + &mut chars, + &mut i, + Rune::Quiet, + vec![ + ("&", Rune::And), + (">", Rune::WriteAll), + (">>", Rune::AddendumAll), + ], + ), ';' => Rune::Continue, '\n' => { j += 1; @@ -212,13 +237,21 @@ impl Readable for Poem { | Rune::And | Rune::Read | Rune::Write - | Rune::Addendum => { + | Rune::Write2 + | Rune::WriteAll + | Rune::Addendum + | Rune::Addendum2 + | Rune::AddendumAll => { if (last == Rune::Couplet || last == Rune::Quiet || last == Rune::And || last == Rune::Read || last == Rune::Write - || last == Rune::Addendum) + || last == Rune::Write2 + || last == Rune::WriteAll + || last == Rune::Addendum + || last == Rune::Addendum2 + || last == Rune::AddendumAll) || verse.is_empty() { return Err(Mishap::ParseMishap(j, i, c)); @@ -226,17 +259,34 @@ impl Readable for Poem { } Rune::Continue => { - if last == Rune::Read || last == Rune::Write || last == Rune::Addendum { + if last == Rune::Read + || last == Rune::Write + || last == Rune::Write2 + || last == Rune::WriteAll + || last == Rune::Addendum + || last == Rune::Addendum2 + || last == Rune::AddendumAll + { return Err(Mishap::ParseMishap(j, i, c)); } } _ => { - if (last == Rune::Read || last == Rune::Write || last == Rune::Addendum) + if (last == Rune::Read + || last == Rune::Write + || last == Rune::Write2 + || last == Rune::WriteAll + || last == Rune::Addendum + || last == Rune::Addendum2 + || last == Rune::AddendumAll) && rune == Rune::None && rune == Rune::Read && rune == Rune::Write + && rune == Rune::Write2 + && rune == Rune::WriteAll && rune == Rune::Addendum + && rune == Rune::Addendum2 + && rune == Rune::AddendumAll && rune == Rune::Couplet && rune == Rune::Quiet && rune == Rune::And @@ -251,7 +301,7 @@ impl Readable for Poem { match rune { // Indicates the end of a word (space dilineated) Rune::Pause => { - verse.add(&mut word); + verse.add(&mut word, channel); } Rune::Remark => { @@ -261,7 +311,7 @@ impl Readable for Poem { // Indicates a string (' or ") Rune::String => { string!(chars, j, i, c, word); - verse.add(&mut word); + verse.add(&mut word, channel); } // Indicates a sub-poem @@ -270,17 +320,23 @@ impl Readable for Poem { } // Indicates a file operation (<, >, or >>) - Rune::Read | Rune::Write | Rune::Addendum => { - verse.add(&mut word); - word.push('<'); - verse.add(&mut word); - verse.io = rune; + Rune::Read + | Rune::Write + | Rune::Write2 + | Rune::WriteAll + | Rune::Addendum + | Rune::Addendum2 + | Rune::AddendumAll => { + verse.add(&mut word, channel); + channel = Some(rune); + verse.io.push(rune); } // These meters indicate the end of a verse Rune::Couplet | Rune::Quiet | Rune::And | Rune::Continue => { - verse.add(&mut word); - poem.add(&mut verse, last, rune, env)?; + channel = None; + verse.add(&mut word, channel); + poem.add(&mut verse, rune, env)?; // append!(poem, last, rune, verse, env); } @@ -290,7 +346,7 @@ impl Readable for Poem { word.append(&mut chars); } - // Any other char i.e. Meter::Else + // Any other char i.e. Rune::Else _ => { word.push(c); } |