summaryrefslogtreecommitdiffstats
path: root/src/poem/read.rs
diff options
context:
space:
mode:
authorRory Dudley2024-05-19 18:50:06 -0600
committerRory Dudley2024-05-19 18:50:06 -0600
commit4b1b8061e79b42128df4f06fd1e439549bf9696b (patch)
tree80db43cf7295937751d61435fb4e60118b8a3ea9 /src/poem/read.rs
parent8756d3e7512c1416cc15a688c62b8f51f030b192 (diff)
downloaddwarvish-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.rs124
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);
}