Parse and display EDN values for NaN, +Infinity and -Infinity. Fixes #232 (#238) r=victorporof

This commit is contained in:
Jordan Santell 2017-02-03 10:14:23 -08:00 committed by GitHub
parent c038c11017
commit 0b20d7691b
3 changed files with 47 additions and 5 deletions

View file

@ -12,6 +12,7 @@
use std::collections::{BTreeSet, BTreeMap, LinkedList}; use std::collections::{BTreeSet, BTreeMap, LinkedList};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::f64::{NAN, INFINITY, NEG_INFINITY};
use num::BigInt; use num::BigInt;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
@ -30,6 +31,14 @@ use types::Value;
pub nil -> Value = pub nil -> Value =
"nil" { Value::Nil } "nil" { Value::Nil }
pub nan -> Value =
"#f NaN" { Value::Float(OrderedFloat(NAN)) }
pub infinity -> Value =
"#f" s:$(sign) "Infinity" {
Value::Float(OrderedFloat(if s == "+" { INFINITY } else { NEG_INFINITY }))
}
pub boolean -> Value = pub boolean -> Value =
"true" { Value::Boolean(true) } / "true" { Value::Boolean(true) } /
"false" { Value::Boolean(false) } "false" { Value::Boolean(false) }
@ -125,7 +134,7 @@ pub map -> Value =
// It's important that float comes before integer or the parser assumes that // It's important that float comes before integer or the parser assumes that
// floats are integers and fails to parse // floats are integers and fails to parse
pub value -> Value = pub value -> Value =
__ v:(nil / boolean / float / bigint / integer / text / keyword / symbol / list / vector / map / set) __ { __ v:(nil / nan / infinity / boolean / float / bigint / integer / text / keyword / symbol / list / vector / map / set) __ {
v v
} }

View file

@ -11,6 +11,7 @@
use std::collections::{BTreeSet, BTreeMap, LinkedList}; use std::collections::{BTreeSet, BTreeMap, LinkedList};
use std::cmp::{Ordering, Ord, PartialOrd}; use std::cmp::{Ordering, Ord, PartialOrd};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::f64;
use symbols; use symbols;
use num::BigInt; use num::BigInt;
@ -54,7 +55,19 @@ impl Display for Value {
Boolean(v) => write!(f, "{}", v), Boolean(v) => write!(f, "{}", v),
Integer(v) => write!(f, "{}", v), Integer(v) => write!(f, "{}", v),
BigInteger(ref v) => write!(f, "{}N", v), BigInteger(ref v) => write!(f, "{}N", v),
Float(OrderedFloat(v)) => write!(f, "{}", v), Float(ref v) => {
// TODO: make sure float syntax is correct.
if *v == OrderedFloat(f64::INFINITY) {
write!(f, "#f {}", "+Infinity")
} else if *v == OrderedFloat(f64::NEG_INFINITY) {
write!(f, "#f {}", "-Infinity")
} else if *v == OrderedFloat(f64::NAN) {
write!(f, "#f {}", "NaN")
} else {
write!(f, "{}", v)
}
}
// TODO: EDN escaping.
Text(ref v) => write!(f, "{}", v), Text(ref v) => write!(f, "{}", v),
PlainSymbol(ref v) => v.fmt(f), PlainSymbol(ref v) => v.fmt(f),
NamespacedSymbol(ref v) => v.fmt(f), NamespacedSymbol(ref v) => v.fmt(f),
@ -266,6 +279,7 @@ mod test {
use std::collections::{BTreeSet, BTreeMap, LinkedList}; use std::collections::{BTreeSet, BTreeMap, LinkedList};
use std::cmp::{Ordering}; use std::cmp::{Ordering};
use std::f64;
use symbols; use symbols;
use num::BigInt; use num::BigInt;
@ -280,7 +294,7 @@ mod test {
#[test] #[test]
fn test_print_edn() { fn test_print_edn() {
assert_eq!("[ 1 2 ( 3.14 ) #{ 4N } { :foo/bar 42 } [ ] :five :six/seven eight nine/ten true false nil ]", assert_eq!("[ 1 2 ( 3.14 ) #{ 4N } { :foo/bar 42 } [ ] :five :six/seven eight nine/ten true false nil #f NaN #f -Infinity #f +Infinity ]",
Value::Vector(vec![ Value::Vector(vec![
Value::Integer(1), Value::Integer(1),
Value::Integer(2), Value::Integer(2),
@ -300,7 +314,10 @@ mod test {
Value::NamespacedSymbol(symbols::NamespacedSymbol::new("nine", "ten")), Value::NamespacedSymbol(symbols::NamespacedSymbol::new("nine", "ten")),
Value::Boolean(true), Value::Boolean(true),
Value::Boolean(false), Value::Boolean(false),
Value::Nil Value::Nil,
Value::Float(OrderedFloat(f64::NAN)),
Value::Float(OrderedFloat(f64::NEG_INFINITY)),
Value::Float(OrderedFloat(f64::INFINITY)),
] ]
).to_string()); ).to_string());
} }

View file

@ -14,6 +14,7 @@ extern crate ordered_float;
use std::collections::{BTreeSet, BTreeMap, LinkedList}; use std::collections::{BTreeSet, BTreeMap, LinkedList};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::f64;
use num::bigint::ToBigInt; use num::bigint::ToBigInt;
use num::traits::{Zero, One}; use num::traits::{Zero, One};
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
@ -50,6 +51,21 @@ fn test_nil() {
assert!(nil("true").is_err()); assert!(nil("true").is_err());
} }
#[test]
fn test_nan() {
assert_eq!(nan("#f NaN").unwrap(), Float(OrderedFloat(f64::NAN)));
assert!(nan("true").is_err());
}
#[test]
fn test_infinity() {
assert_eq!(infinity("#f-Infinity").unwrap(), Float(OrderedFloat(f64::NEG_INFINITY)));
assert_eq!(infinity("#f+Infinity").unwrap(), Float(OrderedFloat(f64::INFINITY)));
assert!(infinity("true").is_err());
}
#[test] #[test]
fn test_boolean() { fn test_boolean() {
assert_eq!(boolean("true").unwrap(), Boolean(true)); assert_eq!(boolean("true").unwrap(), Boolean(true));