1#[derive(Debug, Clone)]
6pub enum SExpr {
7 Atom(String),
8 Str(String),
9 Num(f64),
10 List(Vec<SExpr>),
11}
12
13pub fn read(source: &str) -> Vec<SExpr> {
14 let chars: Vec<char> = source.chars().collect();
15 let mut pos = 0;
16 let mut exprs = Vec::new();
17
18 skip_ws(&chars, &mut pos);
19 while pos < chars.len() {
20 if let Some(expr) = read_expr(&chars, &mut pos) {
21 exprs.push(expr);
22 }
23 skip_ws(&chars, &mut pos);
24 }
25 exprs
26}
27
28fn skip_ws(chars: &[char], pos: &mut usize) {
29 while *pos < chars.len() {
30 match chars[*pos] {
31 ' ' | '\t' | '\n' | '\r' => *pos += 1,
32 ';' => {
33 while *pos < chars.len() && chars[*pos] != '\n' {
34 *pos += 1;
35 }
36 }
37 _ => break,
38 }
39 }
40}
41
42fn read_expr(chars: &[char], pos: &mut usize) -> Option<SExpr> {
43 skip_ws(chars, pos);
44 if *pos >= chars.len() {
45 return None;
46 }
47
48 match chars[*pos] {
49 '(' => Some(read_list(chars, pos)),
50 '"' => Some(read_string(chars, pos)),
51 _ => Some(read_atom_or_num(chars, pos)),
52 }
53}
54
55fn read_list(chars: &[char], pos: &mut usize) -> SExpr {
56 *pos += 1; let mut values = Vec::new();
58 skip_ws(chars, pos);
59 while *pos < chars.len() && chars[*pos] != ')' {
60 if let Some(expr) = read_expr(chars, pos) {
61 values.push(expr);
62 }
63 skip_ws(chars, pos);
64 }
65 if *pos < chars.len() {
66 *pos += 1; }
68 SExpr::List(values)
69}
70
71fn read_string(chars: &[char], pos: &mut usize) -> SExpr {
72 *pos += 1; let mut value = String::new();
74 while *pos < chars.len() && chars[*pos] != '"' {
75 if chars[*pos] == '\\' && *pos + 1 < chars.len() {
76 *pos += 1;
77 match chars[*pos] {
78 'n' => value.push('\n'),
79 't' => value.push('\t'),
80 '\\' => value.push('\\'),
81 '"' => value.push('"'),
82 c => value.push(c),
83 }
84 } else {
85 value.push(chars[*pos]);
86 }
87 *pos += 1;
88 }
89 if *pos < chars.len() {
90 *pos += 1; }
92 SExpr::Str(value)
93}
94
95fn read_atom_or_num(chars: &[char], pos: &mut usize) -> SExpr {
96 let mut value = String::new();
97 while *pos < chars.len() {
98 match chars[*pos] {
99 ' ' | '\t' | '\n' | '\r' | '(' | ')' | ';' => break,
100 c => {
101 value.push(c);
102 *pos += 1;
103 }
104 }
105 }
106
107 if let Ok(n) = value.parse::<f64>() {
109 SExpr::Num(n)
110 } else {
111 SExpr::Atom(value)
112 }
113}