From 40a403c412be52b713a7363840bfa3f507985a9f Mon Sep 17 00:00:00 2001 From: Rory Dudley Date: Fri, 17 May 2024 16:14:42 -0600 Subject: Rewrite of the next! macro This patch replaces the next! macro with a next() function. It serves the same purpose, but instead of only checking for two different runes (a fallback, or one that matches the peek), it can now take a list of runes/characters to look ahead for, in addition to the fallback. --- src/poem/read.rs | 7 ++++--- src/poem/read/parse.rs | 45 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/poem/read.rs b/src/poem/read.rs index afa35e7..35ca2e1 100644 --- a/src/poem/read.rs +++ b/src/poem/read.rs @@ -5,7 +5,8 @@ use super::{ use core::fmt; mod parse; use crate::compose::Environment; -use crate::{next, poem, remark, string}; +use crate::{poem, remark, string}; +use parse::next; #[derive(Debug, PartialEq, Eq)] pub enum Mishap { @@ -191,9 +192,9 @@ impl Readable for Poem { verse.couplet = true; Rune::Read } - '>' => next!(chars, i, Rune::Write, Rune::Addendum, '>'), + '>' => next(&mut chars, &mut i, Rune::Write, vec![('>', Rune::Addendum)]), '|' => Rune::Couplet, - '&' => next!(chars, i, Rune::Quiet, Rune::And, '&'), + '&' => next(&mut chars, &mut i, Rune::Quiet, vec![('&', Rune::And)]), ';' => Rune::Continue, '\n' => { j += 1; diff --git a/src/poem/read/parse.rs b/src/poem/read/parse.rs index 7b01d85..0dbdf0f 100644 --- a/src/poem/read/parse.rs +++ b/src/poem/read/parse.rs @@ -1,20 +1,43 @@ +use crate::poem::elements::rune::Rune; +use std::str::Chars; + /// Look ahead one character in the input /// /// May need to look ahead one character in the input string to determine the /// proper rune. For instance `&`, vs `&&`. -#[macro_export] -macro_rules! next { - ($chars:expr, $i:expr, $otherwise:expr, $rune:expr, $ahead:expr) => { - match $chars.clone().peekable().peek() { - Some(c) if *c == $ahead => { - $chars.next(); - $i += 1; - $rune - } - Some(_) => $otherwise, - None => $otherwise, +/// +/// # Arguments: +/// `chars` - An iterator over the characters in the poem +/// `i` - A counter to keep track of the current column +/// `otherwise` - The rune to return if there are no matches +/// `ahead` - A list of tuples, containing characters to look ahead for, +/// alongside which rune they correspond to +/// +/// # Examples: +/// ``` +/// next(&mut chars, &mut i, Rune::Write, vec![('>', Rune::Addendum)]) +/// next(&mut chars, &mut i, Rune::Quiet, vec![('&', Rune::And)]) +/// ``` +pub fn next(chars: &mut Chars, i: &mut usize, otherwise: Rune, ahead: Vec<(char, Rune)>) -> Rune { + // Try to get the next character in the poem + let next = match chars.peekable().peek() { + Some(c) => *c, + None => { + return otherwise; } }; + + // Check if that next character matches any characters in ahead + for (c, rune) in ahead.iter() { + if next == *c { + chars.into_iter().next(); + *i += 1; + return *rune; + } + } + + // If it doesn't match, return the default + otherwise } /// Keep pushing to the [Word][super::super::elements::word::Word] stack -- cgit v1.2.3