summary refs log tree commit diff
path: root/src/parser.rs
diff options
context:
space:
mode:
authorSophie Forrest <git@sophieforrest.com>2024-09-12 02:31:27 +1200
committerSophie Forrest <git@sophieforrest.com>2024-09-12 02:31:27 +1200
commit14a8735623c7383c1ba5eb4fad13a5588beffabb (patch)
tree8d9a7b6811df58d9e65ce295c7e87b292f39ffd9 /src/parser.rs
parent2acec90f5c1576e3fbceff218f781225ee6efdb7 (diff)
feat(parser): complete offering parser + courseid
Complete courseid and offering parsers. These will be swapped into
the codebase in the next commit.
Diffstat (limited to '')
-rw-r--r--src/parser.rs105
1 files changed, 101 insertions, 4 deletions
diff --git a/src/parser.rs b/src/parser.rs
index c722bfc..87da6be 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -3,13 +3,16 @@
 //! Nom parsers used within the parsing steps.
 
 use nom::{
-	bytes::complete::{tag, take_while},
-	character::complete::multispace0,
-	combinator::map_res,
-	sequence::{pair, preceded},
+	branch::alt,
+	bytes::complete::{tag, take, take_till, take_while},
+	character::complete::{char, multispace0},
+	combinator::{map_res, rest},
+	sequence::{delimited, pair, preceded, separated_pair},
 	IResult,
 };
 
+use crate::{CourseOffering, Trimester};
+
 /// Determines if the provided character is an ascii digit.
 const fn is_decimal_digit(c: char) -> bool {
 	c.is_ascii_digit()
@@ -42,6 +45,62 @@ pub fn course_reference_number(input: &str) -> IResult<&str, u16> {
 	preceded(pair(tag("CRN"), multispace0), crn_digits)(input)
 }
 
+/// Parser that parses a timetable separator.
+///
+/// # Errors
+///
+/// This function will return an error if input does not match expected format by nom.
+pub fn timetable_separator(input: &str) -> IResult<&str, char> {
+	delimited(multispace0, char('\u{2022}'), multispace0)(input)
+}
+
+/// Parses a trimester from an input.
+///
+/// # Errors
+///
+/// This function will return an error if input does not match expected format by nom.
+pub fn trimester(input: &str) -> IResult<&str, Trimester> {
+	map_res(
+		alt((
+			tag("block dates/3"),
+			tag("part year/3"),
+			tag("full year"),
+			take_till(char::is_whitespace),
+		)),
+		Trimester::try_from,
+	)(input)
+}
+
+/// Parses a course offering from an input.
+///
+/// # Errors
+///
+/// This function will return an error if .
+pub fn offering(input: &str) -> IResult<&str, CourseOffering> {
+	let (input, (trimester, crn)) =
+		separated_pair(trimester, timetable_separator, course_reference_number)(input)?;
+	Ok((input, CourseOffering::new(crn, trimester)))
+}
+
+/// Parses a course title from an input.
+///
+/// # Errors
+///
+/// This function will return an error if nom is unable to parse the input. This should only happen
+/// if the input is less than 8 characters.
+pub fn title(input: &str) -> IResult<&str, &str> {
+	take(8usize)(input)
+}
+
+/// Parses a course subtitle from an input.
+///
+/// # Errors
+///
+/// This function will return an error if the subtitle is not preceded by "`\u{2013}` ".
+pub fn subtitle(input: &str) -> IResult<&str, &str> {
+	preceded(tag("\u{2013} "), rest)(input)
+}
+
 #[cfg(test)]
 #[allow(clippy::unwrap_used)]
 mod tests {
@@ -71,4 +130,42 @@ mod tests {
 	fn crn_parser_no_whitespace() {
 		assert_eq!(course_reference_number("CRN615").unwrap().1, 615);
 	}
+
+	#[test]
+	fn offering_parser_alphabetic_durations() {
+		let block_dates = offering("block dates/3 \u{2022} CRN 25341").unwrap();
+
+		assert_eq!(block_dates.1.course_reference_number, 25341);
+		assert_eq!(block_dates.1.trimester, Trimester::BlockDates);
+
+		let part_year = offering("part year/3 \u{2022} CRN 1816").unwrap();
+
+		assert_eq!(part_year.1.course_reference_number, 1816);
+		assert_eq!(part_year.1.trimester, Trimester::PartYear);
+
+		let full_year = offering("full year \u{2022} CRN 19175").unwrap();
+
+		assert_eq!(full_year.1.course_reference_number, 19175);
+		assert_eq!(full_year.1.trimester, Trimester::FullYear);
+	}
+
+	#[test]
+	fn title_parser() {
+		assert_eq!(title("HELT 502 ").unwrap().1, "HELT 502");
+	}
+
+	#[test]
+	fn subtitle_parser() {
+		let parsed_subtitle =
+			subtitle("\u{2013} Identification, Assessment and Control of Hazards and Risks")
+				.unwrap();
+
+		// The dash and space were parsed, and are not remaining data.
+		assert_eq!(parsed_subtitle.0, "");
+		// The actual subtitle.
+		assert_eq!(
+			parsed_subtitle.1,
+			"Identification, Assessment and Control of Hazards and Risks"
+		);
+	}
 }