From 1415c8f9b89699000ef8d864ff8f0e1bebca4a5f Mon Sep 17 00:00:00 2001 From: Rory Dudley Date: Thu, 4 Apr 2024 22:12:14 -0600 Subject: Handle aliases in read() Instead of handling aliases in the recite() function, which requires two loops to handle properly with the current implementation, offload checking for aliases to the read() function. --- src/poem/anthology/alias.rs | 2 +- src/poem/anthology/source.rs | 2 +- src/poem/read.rs | 34 +++++++++++++++++++++------------- src/poem/read/parse.rs | 32 ++++++++++++++++++++++++++++++-- src/poem/recite.rs | 25 +------------------------ 5 files changed, 54 insertions(+), 41 deletions(-) (limited to 'src/poem') diff --git a/src/poem/anthology/alias.rs b/src/poem/anthology/alias.rs index 0183ec2..4c9b7b6 100644 --- a/src/poem/anthology/alias.rs +++ b/src/poem/anthology/alias.rs @@ -39,7 +39,7 @@ pub fn incant(verse: &Verse, out: &mut String, aliases: &mut HashMap i32 { } }; - let poem = match Poem::read(poetry) { + let poem = match Poem::read(poetry, env) { Ok(poem) => poem, Err(e) => { eprintln!("dwvsh: {}", e.to_string().to_lowercase()); diff --git a/src/poem/read.rs b/src/poem/read.rs index d88cf0d..0af7fec 100644 --- a/src/poem/read.rs +++ b/src/poem/read.rs @@ -4,7 +4,8 @@ use super::{ }; use core::fmt; mod parse; -use crate::{next, poem, remark, string}; +use crate::compose::Environment; +use crate::{append, next, poem, remark, string}; #[derive(Debug, PartialEq, Eq)] pub enum Mishap { @@ -51,20 +52,25 @@ impl Appendable for Poem { /// Push a [Verse] to the [Poem] after checking that the [Verse] is not /// empty. Also sets the meter of the [Verse]. fn add(&mut self, verse: &mut Self::Type, last: Rune, meter: Rune) { - if !verse.is_empty() { - verse.meter = meter; - if last == Rune::Couplet || meter == Rune::Couplet { - verse.couplet = true; - } - self.push(verse.clone()); - verse.clear(); + if verse.is_empty() { + return; + } + + // Check the meter + verse.meter = meter; + if last == Rune::Couplet || meter == Rune::Couplet { + verse.couplet = true; } + + // Push verse(s) and clear the current verse stack + self.push(verse.clone()); + verse.clear(); } } /// A [Poem] can parse poetry pub trait Readable { - fn read(poetry: String) -> Result; + fn read(poetry: String, env: &Environment) -> Result; } impl Readable for Poem { @@ -74,7 +80,7 @@ impl Readable for Poem { /// machine-runnable [Poem]. If there is a parse error, [Poem::read] may /// return a [Mishap]. See [Poem::recite][super::recite] for how each /// [Verse] in a [Poem] is called. - fn read(poetry: String) -> Result { + fn read(poetry: String, env: &Environment) -> Result { // Get all the characters in the input string as an iterator let mut chars = poetry.chars().into_iter(); @@ -118,7 +124,8 @@ impl Readable for Poem { } // Push the verse and break - poem.add(&mut verse, last, Rune::None); + // poem.add(&mut verse, last, Rune::None); + append!(poem, last, Rune::None, verse, env); break; } }; @@ -207,7 +214,7 @@ impl Readable for Poem { // Indicates a sub-poem Rune::Poem => { - poem!(chars, j, i, c, verse, word); + poem!(chars, j, i, c, verse, word, env); } // Indicates a file operation (<, >, or >>) @@ -221,7 +228,8 @@ impl Readable for Poem { // 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); + // poem.add(&mut verse, last, rune); + append!(poem, last, rune, verse, env); } // Interpret ~ as $HOME diff --git a/src/poem/read/parse.rs b/src/poem/read/parse.rs index 0836eea..70367c4 100644 --- a/src/poem/read/parse.rs +++ b/src/poem/read/parse.rs @@ -63,7 +63,7 @@ macro_rules! remark { /// 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) => { + ($chars:expr, $j:expr, $i:expr, $c:expr, $verse:expr, $word:expr, $env:expr) => { let token = $c; let mut poetry = Word::new(); loop { @@ -76,7 +76,7 @@ macro_rules! poem { } } } - let sp = Poem::read(poetry.iter().collect()); + let sp = Poem::read(poetry.iter().collect(), $env); let sp = match sp { Ok(sp) => sp, Err(e) => return Err(e), @@ -85,3 +85,31 @@ macro_rules! poem { $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); + } + } + } + }; +} diff --git a/src/poem/recite.rs b/src/poem/recite.rs index 1f24d14..4038e37 100644 --- a/src/poem/recite.rs +++ b/src/poem/recite.rs @@ -4,7 +4,6 @@ use crate::compose::Environment; use crate::path; use crate::poem::anthology; use crate::poem::elements::rune::Rune; -use crate::poem::read::Readable; use std::env; use std::{ io, @@ -26,30 +25,8 @@ impl Reciteable for Poem { // Keep track of pids for background processes let mut pids: Arc>> = Arc::new(Mutex::new(Vec::new())); - // Check for aliases - let mut vv = Poem::new(); - for verse in self.iter() { - let alias = match env.aliases.get(&verse.verb()) { - Some(alias) => alias, - None => { - vv.push(verse.clone()); - continue; - } - } - .to_string(); - - let mut poem = Poem::read(alias).unwrap(); - let len = poem.len(); - for (i, new_verse) in poem.iter_mut().enumerate() { - if verse.clause().is_some() && i + 1 == len { - new_verse.stanza.append(&mut verse.clause().unwrap()); - } - vv.push(new_verse.clone()); - } - } - // Loop through each verse in the poem - for verse in vv.iter() { + for verse in self.iter() { // Verse may need to be mutable let mut verse = verse.clone(); -- cgit v1.2.3