Fix EDN work to pass tests with correct numeric precedence.

This commit is contained in:
Richard Newman 2018-03-05 17:29:20 -08:00
parent d3c0914cf1
commit e2de78d974
3 changed files with 49 additions and 39 deletions

View file

@ -34,13 +34,13 @@ use types::{SpannedValue, Span, ValueAndSpan};
// TODO: Support tagged elements
// TODO: Support discard
nil -> SpannedValue = "nil" { SpannedValue::Nil }
nan -> SpannedValue = "#f" whitespace+ "NaN" { SpannedValue::Float(OrderedFloat(NAN)) }
pub nil -> SpannedValue = "nil" { SpannedValue::Nil }
pub nan -> SpannedValue = "#f" whitespace+ "NaN" { SpannedValue::Float(OrderedFloat(NAN)) }
infinity -> SpannedValue = "#f" whitespace+ s:$(sign) "Infinity"
pub infinity -> SpannedValue = "#f" whitespace+ s:$(sign) "Infinity"
{ SpannedValue::Float(OrderedFloat(if s == "+" { INFINITY } else { NEG_INFINITY })) }
boolean -> SpannedValue
pub boolean -> SpannedValue
= "true" { SpannedValue::Boolean(true) }
/ "false" { SpannedValue::Boolean(false) }
@ -51,29 +51,31 @@ validbase = [3][0-6] / [12][0-9] / [2-9]
hex = [0-9a-fA-F]
sign = [+-]
bigint -> SpannedValue = b:$( sign? digit+ ) "N"
pub bigint -> SpannedValue = b:$( sign? digit+ ) "N"
{ SpannedValue::BigInteger(b.parse::<BigInt>().unwrap()) }
octalinteger -> SpannedValue = "0" i:$( octaldigit+ )
pub octalinteger -> SpannedValue = "0" i:$( octaldigit+ )
{ SpannedValue::Integer(i64::from_str_radix(i, 8).unwrap()) }
hexinteger -> SpannedValue = "0x" i:$( hex+ )
pub hexinteger -> SpannedValue = "0x" i:$( hex+ )
{ SpannedValue::Integer(i64::from_str_radix(i, 16).unwrap()) }
basedinteger -> SpannedValue = b:$( validbase ) "r" i:$( alphanumeric+ )
pub basedinteger -> SpannedValue = b:$( validbase ) "r" i:$( alphanumeric+ )
{ SpannedValue::Integer(i64::from_str_radix(i, b.parse::<u32>().unwrap()).unwrap()) }
integer -> SpannedValue = i:$( sign? digit+ )
pub integer -> SpannedValue = i:$( sign? digit+ ) !("." / ([eE]))
{ SpannedValue::Integer(i.parse::<i64>().unwrap()) }
float -> SpannedValue = f:$(sign? digit+ ("." digit+)? (("e" / "E") sign? digit+)?)
pub float -> SpannedValue = f:$(sign? digit+ ("." digit+)? ([eE] sign? digit+)?)
{ SpannedValue::Float(OrderedFloat(f.parse::<f64>().unwrap())) }
number -> SpannedValue = ( bigint / basedinteger / hexinteger / octalinteger / integer / float )
// TODO: \newline, \return, \space and \tab
special_char = quote / tab
quote = "\\\""
tab = "\\tab"
char = [^"] / special_char
text -> SpannedValue = "\"" t:$( char* ) "\""
pub text -> SpannedValue = "\"" t:$( char* ) "\""
{ SpannedValue::Text(t.to_string()) }
// RFC 3339 timestamps. #inst "1985-04-12T23:20:50.52Z"
@ -116,7 +118,7 @@ uuid_string -> Uuid =
Uuid::parse_str(u).expect("this is a valid UUID string")
}
uuid -> SpannedValue = "#uuid" whitespace+ u:uuid_string
pub uuid -> SpannedValue = "#uuid" whitespace+ u:uuid_string
{ SpannedValue::Uuid(u) }
namespace_divider = "."
@ -134,24 +136,24 @@ plain_symbol_name = symbol_name / "..." / "."
keyword_prefix = ":"
symbol -> SpannedValue =
pub symbol -> SpannedValue =
ns:( sns:$(symbol_namespace) namespace_separator { sns })?
n:$(plain_symbol_name)
{ SpannedValue::from_symbol(ns, n) }
keyword -> SpannedValue =
pub keyword -> SpannedValue =
keyword_prefix
ns:( sns:$(symbol_namespace) namespace_separator { sns })?
n:$(symbol_name)
{ SpannedValue::from_keyword(ns, n) }
list -> SpannedValue = "(" __ v:(value)* __ ")"
pub list -> SpannedValue = "(" __ v:(value)* __ ")"
{ SpannedValue::List(LinkedList::from_iter(v)) }
vector -> SpannedValue = "[" __ v:(value)* __ "]"
pub vector -> SpannedValue = "[" __ v:(value)* __ "]"
{ SpannedValue::Vector(v) }
set -> SpannedValue = "#{" __ v:(value)* __ "}"
pub set -> SpannedValue = "#{" __ v:(value)* __ "}"
{ SpannedValue::Set(BTreeSet::from_iter(v)) }
pair -> (ValueAndSpan, ValueAndSpan) =
@ -159,13 +161,13 @@ pair -> (ValueAndSpan, ValueAndSpan) =
(k, v)
}
map -> SpannedValue = "{" __ v:(pair)* __ "}"
pub map -> SpannedValue = "{" __ v:(pair)* __ "}"
{ SpannedValue::Map(BTreeMap::from_iter(v)) }
// It's important that float comes before integer or the parser assumes that
// floats are integers and fails to parse
pub value -> ValueAndSpan =
__ start:#position v:(nil / nan / infinity / boolean / float / octalinteger / hexinteger / basedinteger / inst / uuid / bigint / integer / text / keyword / symbol / list / vector / map / set) end:#position __ {
__ start:#position v:(nil / nan / infinity / boolean / number / inst / uuid / text / keyword / symbol / list / vector / map / set) end:#position __ {
ValueAndSpan {
inner: v,
span: Span::new(start, end)

View file

@ -163,6 +163,12 @@ impl From<SpannedValue> for Value {
}
}
impl From<ValueAndSpan> for Value {
fn from(src: ValueAndSpan) -> Value {
src.inner.into()
}
}
/// Creates `from_$TYPE` helper functions for Value and SpannedValue,
/// like `from_float()` or `from_ordered_float()`.
macro_rules! def_from {
@ -617,7 +623,10 @@ mod test {
#[test]
fn test_print_edn() {
assert_eq!("1234N", Value::from_bigint("1234").unwrap().to_string());
let string = "[ 1 2 ( 3.14 ) #{ 4N } { foo/bar 42 :baz/boz 43 } [ ] :five :six/seven eight nine/ten true false nil #f NaN #f -Infinity #f +Infinity ]";
let data = Value::Vector(vec![
Value::Integer(1),
Value::Integer(2),

View file

@ -60,7 +60,7 @@ fn s_plain(name: &str) -> Value {
macro_rules! fn_parse_into_value {
($name: ident) => {
fn $name<'a, T>(src: T) -> Result<Value, ParseError> where T: Into<&'a str> {
parse::$name(src.into()).map(|x| x.inner.into())
parse::$name(src.into()).map(|x| x.into())
}
}
}
@ -98,7 +98,7 @@ fn test_nil() {
#[test]
fn test_span_nil() {
assert_eq!(parse::nil("nil").unwrap(), ValueAndSpan {
assert_eq!(parse::value("nil").unwrap(), ValueAndSpan {
inner: SpannedValue::Nil,
span: Span(0, 3)
});
@ -120,7 +120,7 @@ fn test_nan() {
#[test]
fn test_span_nan() {
assert_eq!(parse::nan("#f NaN").unwrap(), ValueAndSpan {
assert_eq!(parse::value("#f NaN").unwrap(), ValueAndSpan {
inner: SpannedValue::Float(OrderedFloat(f64::NAN)),
span: Span(0, 6)
});
@ -150,11 +150,11 @@ fn test_infinity() {
#[test]
fn test_span_infinity() {
assert_eq!(parse::infinity("#f -Infinity").unwrap(), ValueAndSpan {
assert_eq!(parse::value("#f -Infinity").unwrap(), ValueAndSpan {
inner: SpannedValue::Float(OrderedFloat(f64::NEG_INFINITY)),
span: Span(0, 12)
});
assert_eq!(parse::infinity("#f +Infinity").unwrap(), ValueAndSpan {
assert_eq!(parse::value("#f +Infinity").unwrap(), ValueAndSpan {
inner: SpannedValue::Float(OrderedFloat(f64::INFINITY)),
span: Span(0, 12)
});
@ -172,12 +172,12 @@ fn test_boolean() {
#[test]
fn test_span_boolean() {
assert_eq!(parse::boolean("true").unwrap(), ValueAndSpan {
assert_eq!(parse::value("true").unwrap(), ValueAndSpan {
inner: SpannedValue::Boolean(true),
span: Span(0, 4)
});
assert_eq!(parse::boolean("false").unwrap(), ValueAndSpan {
assert_eq!(parse::value("false").unwrap(), ValueAndSpan {
inner: SpannedValue::Boolean(false),
span: Span(0, 5)
});
@ -235,19 +235,19 @@ fn test_octalinteger() {
#[test]
fn test_span_integer() {
assert_eq!(parse::integer("42").unwrap(), ValueAndSpan {
assert_eq!(parse::value("42").unwrap(), ValueAndSpan {
inner: SpannedValue::Integer(42),
span: Span(0, 2)
});
assert_eq!(parse::hexinteger("0xabc111").unwrap(), ValueAndSpan {
assert_eq!(parse::value("0xabc111").unwrap(), ValueAndSpan {
inner: SpannedValue::Integer(11256081),
span: Span(0, 8)
});
assert_eq!(parse::basedinteger("2r111").unwrap(), ValueAndSpan {
assert_eq!(parse::value("2r111").unwrap(), ValueAndSpan {
inner: SpannedValue::Integer(7),
span: Span(0, 5)
});
assert_eq!(parse::octalinteger("011").unwrap(), ValueAndSpan {
assert_eq!(parse::value("011").unwrap(), ValueAndSpan {
inner: SpannedValue::Integer(9),
span: Span(0, 3)
});
@ -266,7 +266,6 @@ fn test_uuid() {
.expect("valid UUID");
let actual = parse::uuid("#uuid \"550e8400-e29b-41d4-a716-446655440000\"")
.expect("parse success")
.inner
.into();
assert_eq!(self::Value::Uuid(expected), actual);
}
@ -291,7 +290,7 @@ fn test_span_bigint() {
let max_i64 = i64::max_value().to_bigint().unwrap();
let bigger = &max_i64 * &max_i64;
assert_eq!(parse::bigint("85070591730234615847396907784232501249N").unwrap(), ValueAndSpan {
assert_eq!(parse::value("85070591730234615847396907784232501249N").unwrap(), ValueAndSpan {
inner: SpannedValue::BigInteger(bigger),
span: Span(0, 39)
});
@ -307,13 +306,13 @@ fn test_float() {
assert_eq!(float("77.88e99").unwrap(), Float(OrderedFloat(77.88e99f64)));
assert_eq!(float("-9.9E-9").unwrap(), Float(OrderedFloat(-9.9E-9f64)));
assert!(float("42").is_err());
assert_eq!(float("42").unwrap(), Float(OrderedFloat(42f64)));
assert!(float("nil").is_err());
}
#[test]
fn test_span_float() {
assert_eq!(parse::float("42.0").unwrap(), ValueAndSpan {
assert_eq!(parse::value("42.0").unwrap(), ValueAndSpan {
inner: SpannedValue::Float(OrderedFloat(42f64)),
span: Span(0, 4)
});
@ -332,7 +331,7 @@ fn test_text() {
#[test]
fn test_span_text() {
assert_eq!(parse::text("\"hello world\"").unwrap(), ValueAndSpan {
assert_eq!(parse::value("\"hello world\"").unwrap(), ValueAndSpan {
inner: SpannedValue::Text("hello world".to_string()),
span: Span(0, 13)
});
@ -359,11 +358,11 @@ fn test_symbol() {
#[test]
fn test_span_symbol() {
assert_eq!(parse::symbol("hello").unwrap(), ValueAndSpan {
assert_eq!(parse::value("hello").unwrap(), ValueAndSpan {
inner: SpannedValue::from_symbol(None, "hello"),
span: Span(0, 5)
});
assert_eq!(parse::symbol("hello/world").unwrap(), ValueAndSpan {
assert_eq!(parse::value("hello/world").unwrap(), ValueAndSpan {
inner: SpannedValue::from_symbol("hello", "world"),
span: Span(0, 11)
});
@ -389,11 +388,11 @@ fn test_keyword() {
#[test]
fn test_span_keyword() {
assert_eq!(parse::keyword(":hello").unwrap(), ValueAndSpan {
assert_eq!(parse::value(":hello").unwrap(), ValueAndSpan {
inner: SpannedValue::from_keyword(None, "hello"),
span: Span(0, 6)
});
assert_eq!(parse::keyword(":hello/world").unwrap(), ValueAndSpan {
assert_eq!(parse::value(":hello/world").unwrap(), ValueAndSpan {
inner: SpannedValue::from_keyword("hello", "world"),
span: Span(0, 12)
});