Sym(String),
/// A value representing a string literal.
Str(String),
+ /// A value representing a single character.
+ Char(char),
/// A value representing an integer. Any number containing no decimal point
/// will be parsed as an `Int`.
Int(i64),
)
);
-named!(atom<&str, Atom>, alt!(string | symbol | number));
+named!(atom<&str, Atom>, alt!(string | symbol | number | character));
named!(string<&str, Atom>,
do_parse!(
fn valid_ident_prefix(ident: &str) -> IResult<&str, ()> {
match ident.chars().next() {
- Some(c) if !c.is_digit(10) && valid_ident_char(c) =>
+ Some(c) if c != '#' && !c.is_digit(10) && valid_ident_char(c) =>
IResult::Done(&ident[1..], ()),
None => IResult::Incomplete(nom::Needed::Unknown),
_ => IResult::Error(nom::ErrorKind::Custom(0)),
)
);
+named!(character<&str, Atom>,
+ do_parse!(
+ opt!(multispace) >>
+ tag_s!("#\\") >>
+ character: take_s!(1) >>
+ (Atom::Char(character.chars().next().unwrap()))
+ )
+);
+
#[cfg(test)]
#[test]
fn test_parse_number() {
assert_eq!(symbol(" ->socket"), IResult::Done("", Atom::Sym("->socket".into())));
assert_eq!(symbol("fib("), IResult::Done("(", Atom::Sym("fib".into())));
+ // We reserve #foo for the implementation to do as it wishes
+ assert!(symbol("#hi").is_err());
+
assert!(symbol("0").is_err());
assert!(symbol("()").is_err());
assert!(symbol("").is_incomplete());
}
+
+#[cfg(test)]
+#[test]
+fn test_parse_char() {
+ assert_eq!(character("#\\\""), IResult::Done("", Atom::Char('"')));
+ assert_eq!(character("#\\ "), IResult::Done("", Atom::Char(' ')));
+ assert_eq!(character(" #\\\\"), IResult::Done("", Atom::Char('\\')));
+
+ assert!(character("#").is_incomplete());
+ assert!(character("a").is_err());
+}