Continue parser experiment
This commit is contained in:
parent
6dbae12315
commit
bdbd1fc412
87
src/lib.rs
87
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};
|
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]
|
||||||
|
Loading…
Reference in New Issue
Block a user