]>
Witch of Git - ess/blob - src/lib.rs
1 //! A lightweight S-expression parser intended for language implementation.
9 use nom
::{digit
, multispace
, IResult
};
11 #[derive(Debug, PartialEq, Clone, PartialOrd)]
13 /// A value representing a symbol. A symbol is an atomic unit
15 /// A value representing a string literal.
17 /// A value representing an integer. Any number containing no decimal point
18 /// will be parsed as an `Int`.
20 /// A value representing a float. Any number containing a decimal point will
21 /// be parsed as a `Float`.
25 #[derive(Debug, PartialEq, Clone, PartialOrd)]
27 /// A wrapper around the atom type
31 /// A list of subexpressions
37 pub fn parse(input
: &str) -> Result
<Sexp
, ()> {
39 IResult
::Done(_
, res
) => Ok(res
),
44 named!(sexp
<&str, Sexp
>,
46 list
=> { |list
| Sexp
::List
{ list
: list
} }
47 | atom
=> { |atom
| Sexp
::Atom
{ atom
: atom
} }
51 named!(list
<&str, Vec
<Sexp
> >,
55 entries
: many0!(sexp
) >>
62 named!(atom
<&str, Atom
>, alt!(string
| symbol
| number
));
64 named!(string
<&str, Atom
>,
68 contents
: take_until_s!("\"") >>
71 (Atom
::Str(contents
.into()))
75 named!(symbol
<&str, Atom
>,
78 peek!(valid_ident_prefix
) >>
79 name
: take_while1_s!(valid_ident_char
) >>
80 (Atom
::Sym(name
.into()))
84 fn valid_ident_prefix(ident
: &str) -> IResult
<&str, ()> {
85 match ident
.chars().next() {
86 Some(c
) if !c
.is_digit(10) && valid_ident_char(c
) =>
87 IResult
::Done(&ident
[1..], ()),
88 None
=> IResult
::Incomplete(nom
::Needed
::Unknown
),
89 _
=> IResult
::Error(nom
::ErrorKind
::Custom(0)),
93 fn valid_ident_char(c
: char) -> bool
{
94 !c
.is_whitespace() && c
!= '
"' && c != '(' && c != ')'
97 named!(number<&str, Atom>,
101 peek!(not!(valid_ident_prefix)) >>
102 (Atom::Int(integral.chars().fold(0, |i, c| i * 10 + c as i64 - '0' as i64)))
108 fn test_parse_number() {
109 assert_eq!(number("0"), IResult::Done("", Atom::Int(0)));
110 assert_eq!(number("123"), IResult::Done("", Atom::Int(123)));
111 assert_eq!(number("0123456789"), IResult::Done("", Atom::Int(123456789)));
112 assert_eq!(number(" 42"), IResult::Done("", Atom::Int(42)));
114 assert!(number(" 42a
").is_err());
115 assert_eq!(number("13()"), IResult::Done("()", Atom::Int(13)));
117 assert!(number("abc
").is_err());
118 assert!(number("()").is_err());
119 assert!(number("").is_incomplete());
124 fn test_parse_ident() {
125 assert_eq!(symbol("+"), IResult::Done("", Atom::Sym("+".into())));
126 assert_eq!(symbol(" nil?
"), IResult::Done("", Atom::Sym("nil?
".into())));
127 assert_eq!(symbol(" ->socket
"), IResult::Done("", Atom::Sym("->socket
".into())));
128 assert_eq!(symbol("fib("), IResult::Done("(", Atom::Sym("fib
".into())));
130 assert!(symbol("0").is_err());
131 assert!(symbol("()").is_err());
132 assert!(symbol("").is_incomplete());
This page took 0.071081 seconds and 5 git commands to generate.