s_expr/
lib.rs

1//! S-Expressions Parser and Printer
2//!
3//! # Parser example
4//!
5//! ```
6//! use s_expr::{Parser, Element, Span};
7//!
8//! let mut parser = Parser::new("(let x 1)");
9//! let r = parser.next().expect("parse data").expect("not end of stream");
10//!
11//! let elements = r.inner.paren().expect("paren group");
12//! assert_eq!(elements[0].inner.atom().and_then(|atom| atom.ident()), Some("let"));
13//! assert_eq!(elements[0].span, Span::on_line(1, 1, 4));
14//! ```
15
16mod data;
17mod loc;
18mod parser;
19mod printer;
20mod tokenizer;
21mod utf8;
22
23pub use data::{ABytes, ADecimal, ANum, Atom, GroupKind};
24pub use loc::{Position, Span};
25pub use parser::{Element, Parser, ParserError, SpannedElement};
26pub use printer::Printer;
27pub use tokenizer::{SpannedToken, Token, TokenError, Tokenizer, TokenizerConfig};
28
29#[cfg(test)]
30mod tests {
31    use super::*;
32
33    const PROG1: &str = r#"
34(define x 1) ; this is a post comment
35; this is a comment
36(define y 0x01_ab)
37(if (zero? x)
38    (strip " " "abc")
39    [1 2 "def\"x"]
40)
41"#;
42
43    const PROG2: &str = r#"
44    (define hello world 123)
45    
46    ; comment space
47    #1234# ( (let x 1) (let y = x + x) 123 x ) "string"
48    
49    ( "this is a quote char: \" " )
50
51    (== (/ (+ 1 2) 3) 1)
52    (pöjk unicode) ; unicode support
53"#;
54
55    fn collect_tokens<'a>(
56        mut tokenizer: Tokenizer<'a>,
57    ) -> Result<Vec<SpannedToken<'a>>, TokenError> {
58        let mut toks = Vec::new();
59        loop {
60            match tokenizer.next() {
61                Ok(Some(tok)) => toks.push(tok),
62                Ok(None) => break,
63                Err(e) => return Err(e),
64            }
65        }
66        return Ok(toks);
67    }
68
69    #[test]
70    fn prog1_tokenize() {
71        let toks1 = collect_tokens(Tokenizer::new(PROG1));
72        assert!(toks1.is_ok())
73    }
74
75    #[test]
76    fn prog2_tokenize() {
77        let toks2 = collect_tokens(Tokenizer::new(PROG2));
78        assert!(toks2.is_ok())
79    }
80
81    #[test]
82    fn prog1_parser() {
83        let mut parser = Parser::new_with_config(PROG1, TokenizerConfig::default().comment(false));
84        {
85            let first_element = parser
86                .next()
87                .expect("parser error")
88                .expect("not end of stream");
89            let e0 = first_element.inner.paren().expect("first group is paren");
90            assert_eq!(e0[0].inner.atom().and_then(|a| a.ident()), Some("define"));
91            assert_eq!(e0[1].inner.atom().and_then(|a| a.ident()), Some("x"));
92            assert_eq!(
93                e0[2]
94                    .inner
95                    .atom()
96                    .and_then(|a| a.number())
97                    .and_then(|n| n.to_u64().ok()),
98                Some(1)
99            )
100        }
101        {
102            let second_element = parser
103                .next()
104                .expect("parser error")
105                .expect("not end of stream");
106            let e0 = second_element.inner.paren().expect("second group is paren");
107            assert_eq!(e0[0].inner.atom().and_then(|a| a.ident()), Some("define"));
108            assert_eq!(e0[1].inner.atom().and_then(|a| a.ident()), Some("y"));
109            assert_eq!(
110                e0[2]
111                    .inner
112                    .atom()
113                    .and_then(|a| a.number())
114                    .and_then(|n| n.to_u64().ok()),
115                Some(0x01_ab)
116            )
117        }
118
119        {
120            let third_element = parser
121                .next()
122                .expect("parser error")
123                .expect("not end of stream");
124            let e0 = third_element.inner.paren().expect("third group is paren");
125            assert_eq!(e0[0].inner.atom().and_then(|a| a.ident()), Some("if"));
126            let conditional = e0[1].inner.paren().expect("conditional");
127            assert_eq!(
128                conditional[0].inner.atom().and_then(|a| a.ident()),
129                Some("zero?")
130            );
131            assert_eq!(
132                conditional[1].inner.atom().and_then(|a| a.ident()),
133                Some("x")
134            );
135            let then_expr = e0[2].inner.paren().expect("then");
136            assert_eq!(
137                then_expr[0].inner.atom().and_then(|a| a.ident()),
138                Some("strip")
139            );
140            assert_eq!(
141                then_expr[1]
142                    .inner
143                    .atom()
144                    .and_then(|a| a.string())
145                    .map(|s| s.to_string()),
146                Some(" ".to_string())
147            );
148            assert_eq!(
149                then_expr[2]
150                    .inner
151                    .atom()
152                    .and_then(|a| a.string())
153                    .map(|s| s.to_string()),
154                Some("abc".to_string())
155            );
156
157            let _else_expr = e0[3].inner.bracket().expect("else");
158        }
159    }
160}