From bdbd1fc412fbef3d2ffd011b928fb5ce8b32a6bf Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 23 Feb 2024 08:23:35 -0500 Subject: [PATCH] Continue parser experiment --- src/lib.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 68e2724..7481dca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,19 +1,34 @@ -use std::fmt::{self, Display, Formatter}; +use std::{ + collections::BTreeMap, + fmt::{self, Display, Formatter}, + ops::Range, +}; use chumsky::{prelude::*, Parser}; #[derive(Clone, Debug, PartialEq)] pub enum Value { Boolean(bool), + Float(f64), Integer(i64), + List(Vec), + Map(BTreeMap), + Range(Range), String(String), } +#[derive(Clone, Debug, PartialEq)] +pub struct Identifier(String); + impl Display for Value { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Value::Boolean(boolean) => write!(f, "{boolean}"), + Value::Float(float) => write!(f, "{float}"), Value::Integer(integer) => write!(f, "{integer}"), + Value::List(_list) => todo!(), + Value::Map(_map) => todo!(), + Value::Range(range) => write!(f, "{}..{}", range.start, range.end), Value::String(string) => write!(f, "{string}"), } } @@ -24,6 +39,25 @@ pub fn parser() -> impl Parser> { .or(just("false")) .map(|s: &str| Value::Boolean(s.parse().unwrap())); + let float_numeric = just('-') + .or_not() + .then(text::int(10)) + .then(just('.').then(text::digits(10))) + .map(|((negative, before), (_, after))| { + let combined = before + "." + &after; + + if negative.is_some() { + Value::Float(-combined.parse::().unwrap()) + } else { + Value::Float(combined.parse().unwrap()) + } + }); + + let float_other = choice((just("Infinity"), just("-Infinity"), just("NaN"))) + .map(|text| Value::Float(text.parse().unwrap())); + + let float = choice((float_numeric, float_other)); + let integer = just('-') .or_not() .then(text::int(10).padded()) @@ -36,7 +70,7 @@ pub fn parser() -> impl Parser> { }) .map(|s: String| Value::Integer(s.parse().unwrap())); - let delimited_string = |delimiter: char| { + let delimited_string = |delimiter| { just(delimiter) .ignore_then(none_of(delimiter).repeated()) .then_ignore(just(delimiter)) @@ -49,7 +83,7 @@ pub fn parser() -> impl Parser> { delimited_string('`'), )); - boolean.or(integer).or(string).then_ignore(end()) + boolean.or(float).or(integer).or(string).then_ignore(end()) } #[cfg(test)] @@ -58,12 +92,55 @@ mod tests { #[test] fn parse_true() { - assert_eq!(parser().parse("true"), Ok(Value::Boolean(true))) + assert_eq!(parser().parse("true"), Ok(Value::Boolean(true))); } #[test] fn parse_false() { - assert_eq!(parser().parse("false"), Ok(Value::Boolean(false))) + assert_eq!(parser().parse("false"), Ok(Value::Boolean(false))); + } + + #[test] + fn parse_positive_float() { + assert_eq!(parser().parse("0.0"), Ok(Value::Float(0.0))); + assert_eq!(parser().parse("42.0"), Ok(Value::Float(42.0))); + assert_eq!( + parser().parse(f64::MAX.to_string() + ".0"), + Ok(Value::Float(f64::MAX)) + ); + assert_eq!( + parser().parse(f64::MIN_POSITIVE.to_string()), + Ok(Value::Float(f64::MIN_POSITIVE)) + ); + } + + #[test] + fn parse_negative_float() { + assert_eq!(parser().parse("-0.0"), Ok(Value::Float(-0.0))); + assert_eq!(parser().parse("-42.0"), Ok(Value::Float(-42.0))); + assert_eq!( + parser().parse(f64::MIN.to_string() + ".0"), + Ok(Value::Float(f64::MIN)) + ); + assert_eq!( + parser().parse("-".to_string() + &f64::MIN_POSITIVE.to_string()), + Ok(Value::Float(-f64::MIN_POSITIVE)) + ); + } + + #[test] + fn parse_other_float() { + assert_eq!(parser().parse("Infinity"), Ok(Value::Float(f64::INFINITY))); + assert_eq!( + parser().parse("-Infinity"), + Ok(Value::Float(f64::NEG_INFINITY)) + ); + + if let Value::Float(float) = parser().parse("NaN").unwrap() { + assert!(float.is_nan()) + } else { + panic!("Expected a float.") + } } #[test]