summaryrefslogtreecommitdiffstats
path: root/src/poem/read.rs
diff options
context:
space:
mode:
authorRory Dudley2024-05-20 11:27:45 -0600
committerRory Dudley2024-05-20 11:27:45 -0600
commit8a7af4aacc0d67a9887ca1fd665b1694fd62a8ca (patch)
tree8bd0ec21d289e558925d15663b490b9873f257ea /src/poem/read.rs
parent1bb25591b77a14a17bd05d79316ce703bcbcc3a6 (diff)
downloaddwarvish-8a7af4aacc0d67a9887ca1fd665b1694fd62a8ca.tar.gz
Allow aliases with the same name as their verb
Previously, when trying to add an alias that used the same name as its command, an infinite recursion loop would occur, and the program would panic after the call stack got too deep. For instance, something like: alias grep='grep --color=always' would cause it to panic. This patch adds a new field to the Environment struct called 'cs' (for call stack), which can be used to keep track of how many levels deep into the Poem::read() function we are in. At the moment, it only allows going two levels deep, but since it's just a u8 value, this could be increased in the future. The above example now works correctly, but it does mean that aliases within aliases are not possible, currently.
Diffstat (limited to 'src/poem/read.rs')
-rw-r--r--src/poem/read.rs24
1 files changed, 17 insertions, 7 deletions
diff --git a/src/poem/read.rs b/src/poem/read.rs
index da13f76..3c4a720 100644
--- a/src/poem/read.rs
+++ b/src/poem/read.rs
@@ -42,8 +42,12 @@ 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, env: &Environment)
- -> Result<(), Mishap>;
+ fn add(
+ &mut self,
+ verse: &mut Self::Type,
+ meter: Rune,
+ env: &mut Environment,
+ ) -> Result<(), Mishap>;
}
impl Appendable for Poem {
@@ -57,7 +61,7 @@ impl Appendable for Poem {
&mut self,
verse: &mut Self::Type,
meter: Rune,
- env: &Environment,
+ env: &mut Environment,
) -> Result<(), Mishap> {
if verse.is_empty() {
return Ok(());
@@ -81,10 +85,16 @@ impl Appendable for Poem {
// Check for aliases
match env.aliases.get(&verse.verb()) {
- Some(alias) => {
+ Some(alias) if env.cs == 0 => {
+ // Increase the callstack
+ env.cs = 1;
+
// Interpret the alias (could be a complex poem)
let mut poem = Poem::read(alias.to_string(), env)?;
+ // Decrease the callstack
+ env.cs = 0;
+
// Try and get the last verse
let lv = match poem.last_mut() {
Some(lv) => lv,
@@ -109,7 +119,7 @@ impl Appendable for Poem {
self.push(v.clone());
}
}
- None => {
+ Some(_) | None => {
// Push verse(s)
self.push(verse.clone());
}
@@ -125,7 +135,7 @@ impl Appendable for Poem {
/// A [Poem] can parse poetry
pub trait Readable {
- fn read(poetry: String, env: &Environment) -> Result<Poem, Mishap>;
+ fn read(poetry: String, env: &mut Environment) -> Result<Poem, Mishap>;
}
impl Readable for Poem {
@@ -135,7 +145,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, env: &Environment) -> Result<Poem, Mishap> {
+ fn read(poetry: String, env: &mut Environment) -> Result<Poem, Mishap> {
// Get all the characters in the input string as an iterator
let mut chars = poetry.chars().into_iter();