Plan parsing

This commit is contained in:
Daniel Flanagan 2024-07-06 14:18:57 -05:00
parent 00944b5db9
commit df4cd420ad

View file

@ -2,6 +2,7 @@ mod song {
use std::{ use std::{
collections::{BTreeMap, VecDeque}, collections::{BTreeMap, VecDeque},
str::FromStr, str::FromStr,
sync::OnceLock,
}; };
use regex::Regex; use regex::Regex;
@ -19,7 +20,7 @@ mod song {
} }
/// Sequence of verse names. /// Sequence of verse names.
pub type Plan = Vec<String>; pub type Plan = VecDeque<String>;
pub struct Song { pub struct Song {
pub name: String, pub name: String,
@ -29,7 +30,7 @@ mod song {
} }
impl Song { impl Song {
pub fn plan(&self, plan_name: Option<String>) -> &Vec<String> { pub fn plan(&self, plan_name: Option<String>) -> &VecDeque<String> {
plan_name plan_name
.map(|plan_name| { .map(|plan_name| {
self.other_plans self.other_plans
@ -41,11 +42,15 @@ mod song {
} }
#[derive(Debug)] #[derive(Debug)]
pub enum SongParseError { pub struct SourceRef {
EmptyString, line_number: usize,
} }
const REGEX_TWO_NEWLINES_WITH_ARBITRARY_SURROUNDING_WHITESPACE: &str = r"\s*[\n\r]\s*[\n\r]\s*"; #[derive(Debug)]
pub enum SongParseError {
EmptyString,
InvalidMetadata(SourceRef),
}
impl FromStr for Song { impl FromStr for Song {
type Err = SongParseError; type Err = SongParseError;
@ -55,7 +60,8 @@ mod song {
return Err(SongParseError::EmptyString); return Err(SongParseError::EmptyString);
} }
let re = Regex::new(REGEX_TWO_NEWLINES_WITH_ARBITRARY_SURROUNDING_WHITESPACE).unwrap(); static HUNK_REGEX: OnceLock<Regex> = OnceLock::new();
let re = HUNK_REGEX.get_or_init(|| Regex::new(r"\s*[\n\r]\s*[\n\r]\s*").unwrap());
let mut hunks = VecDeque::new(); let mut hunks = VecDeque::new();
let mut last_end: usize = 0; let mut last_end: usize = 0;
@ -68,14 +74,25 @@ mod song {
// process header // process header
let mut header_lines = hunks.pop_front().unwrap().lines(); let mut header_lines = hunks.pop_front().unwrap().lines();
let name = header_lines.next().unwrap().trim().to_owned(); let name = header_lines.next().unwrap().trim().to_owned();
let mut other_plans = BTreeMap::new();
for line in header_lines { for (line_number, line) in header_lines.enumerate() {
if line.starts_with("map(") {
match line.find(":") {
Some(i) => {}
None => {
return Err(SongParseError::InvalidMetadata(SourceRef { line_number }))
}
}
}
// map(band2): slide1, slide2 // map(band2): slide1, slide2
// band2: slide1, slide2 // band2: slide1, slide2
} }
let mut verses = BTreeMap::new(); let mut verses = BTreeMap::new();
let mut default_plan = Plan::new();
// process verses // process verses
for hunk in hunks { for hunk in hunks {
let mut verse_contents = hunk; let mut verse_contents = hunk;
@ -86,14 +103,15 @@ mod song {
} else { } else {
format!("Generated Verse {}", verses.len() + 1).to_owned() format!("Generated Verse {}", verses.len() + 1).to_owned()
}; };
verses.insert(verse_name, Verse::new(verse_contents.to_owned())); verses.insert(verse_name.clone(), Verse::new(verse_contents.to_owned()));
default_plan.push_back(verse_name.clone());
} }
Ok(Self { Ok(Self {
name, name,
verses, verses,
other_plans: BTreeMap::new(), other_plans,
default_plan: vec![], default_plan,
}) })
} }
} }
@ -117,8 +135,8 @@ mod song {
}) })
); );
assert_eq!(song.verses.len(), 1); assert_eq!(song.verses.len(), 1);
assert_eq!(song.default_plan.len(), 1);
assert_eq!(song.default_plan[0], "Generated Verse 1"); assert_eq!(song.default_plan[0], "Generated Verse 1");
assert_eq!(song.default_plan.len(), 1);
} }
} }
} }