summaryrefslogtreecommitdiffstats
path: root/src/poem
diff options
context:
space:
mode:
authorRory Dudley2024-04-04 22:12:14 -0600
committerRory Dudley2024-04-04 22:12:14 -0600
commit1415c8f9b89699000ef8d864ff8f0e1bebca4a5f (patch)
tree64093c0eded6a6f28105dbd743729b4075d32889 /src/poem
parentbadbba41476cd6fd424042c48681acde82227ba6 (diff)
downloaddwarvish-1415c8f9b89699000ef8d864ff8f0e1bebca4a5f.tar.gz
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.
Diffstat (limited to 'src/poem')
-rw-r--r--src/poem/anthology/alias.rs2
-rw-r--r--src/poem/anthology/source.rs2
-rw-r--r--src/poem/read.rs34
-rw-r--r--src/poem/read/parse.rs32
-rw-r--r--src/poem/recite.rs25
5 files changed, 54 insertions, 41 deletions
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<String, Str
}
if verse.couplet {
- *out = lines.join("\n");
+ *out = format!("{}\n", lines.join("\n"));
} else {
println!("{}", lines.join("\n"));
}
diff --git a/src/poem/anthology/source.rs b/src/poem/anthology/source.rs
index 77d1330..182fef4 100644
--- a/src/poem/anthology/source.rs
+++ b/src/poem/anthology/source.rs
@@ -34,7 +34,7 @@ pub fn incant(verse: &Verse, out: &mut String, env: &mut Environment) -> 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<Poem, Mishap>;
+ fn read(poetry: String, env: &Environment) -> Result<Poem, Mishap>;
}
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<Poem, Mishap> {
+ fn read(poetry: String, env: &Environment) -> Result<Poem, Mishap> {
// 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<Mutex<Vec<i32>>> = 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();