edn 0.3.0

An EDN (Extensible Data Notation) parser.
Documentation
extern crate edn;
extern crate ordered_float;

use edn::Value;
use edn::parser::{Error, Parser};

#[test]
fn test_read_empty() {
    let mut parser = Parser::new("");
    assert_eq!(parser.read(), None);
}

#[test]
fn test_read_integers() {
    let mut parser = Parser::new("0 -0 +0 +1234 1234 -1234 +9223372036854775807
                                  -9223372036854775808");
    assert_eq!(parser.read(), Some(Ok(Value::Integer(0))));
    assert_eq!(parser.read(), Some(Ok(Value::Integer(0))));
    assert_eq!(parser.read(), Some(Ok(Value::Integer(0))));
    assert_eq!(parser.read(), Some(Ok(Value::Integer(1234))));
    assert_eq!(parser.read(), Some(Ok(Value::Integer(1234))));
    assert_eq!(parser.read(), Some(Ok(Value::Integer(-1234))));
    assert_eq!(parser.read(), Some(Ok(Value::Integer(9223372036854775807))));
    assert_eq!(parser.read(), Some(Ok(Value::Integer(-9223372036854775808))));
    assert_eq!(parser.read(), None);
}

#[test]
fn test_read_floats() {
    use ordered_float::OrderedFloat;

    let mut parser = Parser::new("0. 0.0 -0.0 +0.0 1.23 +1.23 -1.23 .125");
    assert_eq!(parser.read(), Some(Ok(Value::Float(OrderedFloat(0.0)))));
    assert_eq!(parser.read(), Some(Ok(Value::Float(OrderedFloat(0.0)))));
    assert_eq!(parser.read(), Some(Ok(Value::Float(OrderedFloat(0.0)))));
    assert_eq!(parser.read(), Some(Ok(Value::Float(OrderedFloat(0.0)))));
    assert_eq!(parser.read(), Some(Ok(Value::Float(OrderedFloat(1.23)))));
    assert_eq!(parser.read(), Some(Ok(Value::Float(OrderedFloat(1.23)))));
    assert_eq!(parser.read(), Some(Ok(Value::Float(OrderedFloat(-1.23)))));
    assert_eq!(parser.read(), Some(Ok(Value::Float(OrderedFloat(0.125)))));
    assert_eq!(parser.read(), None);
}

#[test]
fn test_read_chars() {
    let mut parser = Parser::new("\\a \\Ï€ \\newline \\return \\space \\tab");
    assert_eq!(parser.read(), Some(Ok(Value::Char('a'))));
    assert_eq!(parser.read(), Some(Ok(Value::Char('Ï€'))));
    assert_eq!(parser.read(), Some(Ok(Value::Char('\n'))));
    assert_eq!(parser.read(), Some(Ok(Value::Char('\r'))));
    assert_eq!(parser.read(), Some(Ok(Value::Char(' '))));
    assert_eq!(parser.read(), Some(Ok(Value::Char('\t'))));
    assert_eq!(parser.read(), None);

    let mut parser = Parser::new("  \\foo  ");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 2,
        hi: 6,
        message: "invalid char literal `\\foo`".into()})));
}

#[test]
fn test_read_strings() {
    let mut parser = Parser::new(r#"
"foo"
"bar"
"baz
quux"
"\t\r\n\\\""
"#);
    assert_eq!(parser.read(), Some(Ok(Value::String("foo".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::String("bar".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::String("baz\nquux".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::String("\t\r\n\\\"".into()))));
    assert_eq!(parser.read(), None);

    let mut parser = Parser::new("\"foo\\x\"");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 4,
        hi: 6,
        message: "invalid string escape `\\x`".into()})));

    let mut parser = Parser::new("   \"foo");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 3,
        hi: 7,
        message: "expected closing `\"`, found EOF".into()})));
}

#[test]
fn test_read_symbols() {
    let mut parser = Parser::new(r#"
foo
+foo
-foo
.foo
.*+!-_?$%&=<>:#123
+
-
namespaced/symbol
/
"#);
    assert_eq!(parser.read(), Some(Ok(Value::Symbol("foo".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Symbol("+foo".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Symbol("-foo".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Symbol(".foo".into()))));
    assert_eq!(parser.read(),
               Some(Ok(Value::Symbol(".*+!-_?$%&=<>:#123".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Symbol("+".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Symbol("-".into()))));
    assert_eq!(parser.read(),
               Some(Ok(Value::Symbol("namespaced/symbol".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Symbol("/".into()))));
    assert_eq!(parser.read(), None);
}

#[test]
fn test_read_keywords() {
    let mut parser = Parser::new(r#"
:foo
:+foo
:-foo
:.foo
:.*+!-_?$%&=<>:#123
:+
:-
"#);
    assert_eq!(parser.read(), Some(Ok(Value::Keyword("foo".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Keyword("+foo".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Keyword("-foo".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Keyword(".foo".into()))));
    assert_eq!(parser.read(),
               Some(Ok(Value::Keyword(".*+!-_?$%&=<>:#123".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Keyword("+".into()))));
    assert_eq!(parser.read(), Some(Ok(Value::Keyword("-".into()))));
    assert_eq!(parser.read(), None);
}

#[test]
fn test_read_booleans_and_nil() {
    let mut parser = Parser::new("true false nil");
    assert_eq!(parser.read(), Some(Ok(Value::Boolean(true))));
    assert_eq!(parser.read(), Some(Ok(Value::Boolean(false))));
    assert_eq!(parser.read(), Some(Ok(Value::Nil)));
    assert_eq!(parser.read(), None);
}

#[test]
fn test_read_commas() {
    let mut parser = Parser::new(",, true ,false,");
    assert_eq!(parser.read(), Some(Ok(Value::Boolean(true))));
    assert_eq!(parser.read(), Some(Ok(Value::Boolean(false))));
    assert_eq!(parser.read(), None);
}

#[test]
fn test_read_lists() {
    let mut parser = Parser::new("() (1 2 3) (true, false, nil)
                                  (((\"foo\" \"bar\")))");

    assert_eq!(parser.read(), Some(Ok(Value::List(vec![]))));

    assert_eq!(parser.read(), Some(Ok(Value::List(vec![
        Value::Integer(1),
        Value::Integer(2),
        Value::Integer(3)]))));

    assert_eq!(parser.read(), Some(Ok(Value::List(vec![
        Value::Boolean(true),
        Value::Boolean(false),
        Value::Nil]))));

    assert_eq!(parser.read(), Some(Ok(
        Value::List(vec![
            Value::List(vec![
                Value::List(vec![
                    Value::String("foo".into()),
                    Value::String("bar".into())])])]))));

    assert_eq!(parser.read(), None);

    let mut parser = Parser::new("((  \\foo ))");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 4,
        hi: 8,
        message: "invalid char literal `\\foo`".into()})));

    let mut parser = Parser::new("( (  1 2 3");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 2,
        hi: 10,
        message: "unclosed `(`".into()})));
}

#[test]
fn test_read_vectors() {
    let mut parser = Parser::new("[] [1 2 3] [true, false, nil]
                                  [[[\"foo\" \"bar\"]]]");

    assert_eq!(parser.read(), Some(Ok(Value::Vector(vec![]))));

    assert_eq!(parser.read(), Some(Ok(Value::Vector(vec![
        Value::Integer(1),
        Value::Integer(2),
        Value::Integer(3)]))));

    assert_eq!(parser.read(), Some(Ok(Value::Vector(vec![
        Value::Boolean(true),
        Value::Boolean(false),
        Value::Nil]))));

    assert_eq!(parser.read(), Some(Ok(
        Value::Vector(vec![
            Value::Vector(vec![
                Value::Vector(vec![
                    Value::String("foo".into()),
                    Value::String("bar".into())])])]))));

    assert_eq!(parser.read(), None);

    let mut parser = Parser::new("[[  \\foo ]]");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 4,
        hi: 8,
        message: "invalid char literal `\\foo`".into()})));

    let mut parser = Parser::new("[ [  1 2 3");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 2,
        hi: 10,
        message: "unclosed `[`".into()})));
}

#[test]
fn test_read_maps() {
    use std::collections::BTreeMap;

    let mut parser = Parser::new("{} {1 2} {true, false}
                                  {{\"foo\" \"bar\"} \"baz\"}");

    assert_eq!(parser.read(), Some(Ok(Value::Map(BTreeMap::new()))));

    assert_eq!(parser.read(), Some(Ok(Value::Map({
        let mut map = BTreeMap::new();
        map.insert(Value::Integer(1), Value::Integer(2));
        map
    }))));

    assert_eq!(parser.read(), Some(Ok(Value::Map({
        let mut map = BTreeMap::new();
        map.insert(Value::Boolean(true), Value::Boolean(false));
        map
    }))));

    assert_eq!(parser.read(), Some(Ok(Value::Map({
        let mut map = BTreeMap::new();
        map.insert(Value::Map({
            let mut map = BTreeMap::new();
            map.insert(Value::String("foo".into()),
                       Value::String("bar".into()));
            map
        }), Value::String("baz".into()));
        map
    }))));

    let mut parser = Parser::new("{\\foo true}");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 1,
        hi: 5,
        message: "invalid char literal `\\foo`".into()})));

    let mut parser = Parser::new("{ { 1 2 3");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 2,
        hi: 9,
        message: "unclosed `{`".into()})));

    let mut parser = Parser::new("{1 2 3}");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 0,
        hi: 7,
        message: "odd number of items in a Map".into()})));

    let mut parser = Parser::new("{{1 2 3}}");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 1,
        hi: 8,
        message: "odd number of items in a Map".into()})));
}

#[test]
fn test_read_sets() {
    let mut parser = Parser::new("#{} #{1 2 2 3 3 3} #{true, false, nil}
                                  #{#{#{\"foo\" \"bar\"}}}");

    assert_eq!(parser.read(),
               Some(Ok(Value::Set([].iter().cloned().collect()))));

    assert_eq!(parser.read(), Some(Ok(Value::Set(
        [Value::Integer(1),
         Value::Integer(2),
         Value::Integer(3)].iter().cloned().collect()))));

    assert_eq!(parser.read(), Some(Ok(Value::Set(
        [Value::Boolean(true),
         Value::Boolean(false),
         Value::Nil].iter().cloned().collect()))));

    assert_eq!(parser.read(), Some(Ok(
        Value::Set(
            [Value::Set(
                [Value::Set(
                    [Value::String("foo".into()),
                     Value::String("bar".into())
                     ].iter().cloned().collect())
                 ].iter().cloned().collect())
             ].iter().cloned().collect()))));

    assert_eq!(parser.read(), None);

    let mut parser = Parser::new("#{#{  \\foo }}");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 6,
        hi: 10,
        message: "invalid char literal `\\foo`".into()})));

    let mut parser = Parser::new("#{ #{ 1 2 3");
    assert_eq!(parser.read(), Some(Err(Error {
        lo: 3,
        hi: 11,
        message: "unclosed `#{`".into()})));
}

#[test]
fn test_tagged_values() {
    let mut parser = Parser::new(r#"
#color (255, 31, 191)
#foo/bar :baz
#nested #tags "works"
#noclose
"#);
    assert_eq!(parser.read(),
               Some(Ok(Value::Tagged("color".into(),
                                     Box::new(Value::List(vec![Value::Integer(255),
                                                               Value::Integer(31),
                                                               Value::Integer(191)]))))));
    assert_eq!(parser.read(),
               Some(Ok(Value::Tagged("foo/bar".into(), Box::new(Value::Keyword("baz".into()))))));
    assert_eq!(parser.read(),
               Some(Ok(Value::Tagged("nested".into(),
                                     Box::new(Value::Tagged("tags".into(),
                                                            Box::new(Value::String("works"
                                                                .into()))))))));
    assert_eq!(parser.read(),
               Some(Err(Error {
                   lo: 60,
                   hi: 68,
                   message: "malformed tagged value".into(),
               })));

    assert_eq!(parser.read(), None);
}