Continue parser experiment

This commit is contained in:
Jeff 2024-02-23 08:23:35 -05:00
parent 6dbae12315
commit bdbd1fc412

View File

@ -1,19 +1,34 @@
use std::fmt::{self, Display, Formatter}; use std::{
collections::BTreeMap,
fmt::{self, Display, Formatter},
ops::Range,
};
use chumsky::{prelude::*, Parser}; use chumsky::{prelude::*, Parser};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Value { pub enum Value {
Boolean(bool), Boolean(bool),
Float(f64),
Integer(i64), Integer(i64),
List(Vec<Value>),
Map(BTreeMap<Identifier, Value>),
Range(Range<i64>),
String(String), String(String),
} }
#[derive(Clone, Debug, PartialEq)]
pub struct Identifier(String);
impl Display for Value { impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self { match self {
Value::Boolean(boolean) => write!(f, "{boolean}"), Value::Boolean(boolean) => write!(f, "{boolean}"),
Value::Float(float) => write!(f, "{float}"),
Value::Integer(integer) => write!(f, "{integer}"), 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}"), Value::String(string) => write!(f, "{string}"),
} }
} }
@ -24,6 +39,25 @@ pub fn parser() -> impl Parser<char, Value, Error = Simple<char>> {
.or(just("false")) .or(just("false"))
.map(|s: &str| Value::Boolean(s.parse().unwrap())); .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::<f64>().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('-') let integer = just('-')
.or_not() .or_not()
.then(text::int(10).padded()) .then(text::int(10).padded())
@ -36,7 +70,7 @@ pub fn parser() -> impl Parser<char, Value, Error = Simple<char>> {
}) })
.map(|s: String| Value::Integer(s.parse().unwrap())); .map(|s: String| Value::Integer(s.parse().unwrap()));
let delimited_string = |delimiter: char| { let delimited_string = |delimiter| {
just(delimiter) just(delimiter)
.ignore_then(none_of(delimiter).repeated()) .ignore_then(none_of(delimiter).repeated())
.then_ignore(just(delimiter)) .then_ignore(just(delimiter))
@ -49,7 +83,7 @@ pub fn parser() -> impl Parser<char, Value, Error = Simple<char>> {
delimited_string('`'), delimited_string('`'),
)); ));
boolean.or(integer).or(string).then_ignore(end()) boolean.or(float).or(integer).or(string).then_ignore(end())
} }
#[cfg(test)] #[cfg(test)]
@ -58,12 +92,55 @@ mod tests {
#[test] #[test]
fn parse_true() { fn parse_true() {
assert_eq!(parser().parse("true"), Ok(Value::Boolean(true))) assert_eq!(parser().parse("true"), Ok(Value::Boolean(true)));
} }
#[test] #[test]
fn parse_false() { 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] #[test]