1use std::str::Chars;
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum Atom {
5 S(String),
6 Q(String),
7 I(i32),
8 F(f32),
9 B(bool),
10}
11
12#[derive(Debug, Clone, PartialEq)]
13pub enum Sexp {
14 Atom(Atom),
15 List(Vec<Sexp>),
16}
17
18#[derive(Debug)]
19pub enum ParseError {
20 UnexpectedEOF,
21 InvalidToken(String),
22 UnclosedString,
23 InvalidNumber(String),
24}
25
26pub struct Parser<'a> {
27 chars: Chars<'a>,
28 current: Option<char>,
29}
30
31impl<'a> Parser<'a> {
32 pub fn new(input: &'a str) -> Self {
33 let mut chars = input.chars();
34 let current = chars.next();
35 Parser { chars, current }
36 }
37
38 fn bump(&mut self) {
39 self.current = self.chars.next();
40 }
41
42 fn skip_whitespace(&mut self) {
43 while matches!(self.current, Some(c) if c.is_whitespace()) {
44 self.bump();
45 }
46 }
47
48 pub fn parse(&mut self) -> Result<Sexp, ParseError> {
49 self.skip_whitespace();
50 match self.current {
51 Some('(') => self.parse_list(),
52 Some('"') => self.parse_quoted_string(),
53 Some(_) => self.parse_atom(),
54 None => Err(ParseError::UnexpectedEOF),
55 }
56 }
57
58 fn parse_list(&mut self) -> Result<Sexp, ParseError> {
59 self.bump(); let mut items = Vec::new();
61
62 loop {
63 self.skip_whitespace();
64 match self.current {
65 Some(')') => {
66 self.bump(); break;
68 }
69 Some(_) => {
70 let expr = self.parse()?;
71 items.push(expr);
72 }
73 None => return Err(ParseError::UnexpectedEOF),
74 }
75 }
76 Ok(Sexp::List(items))
77 }
78
79 fn parse_quoted_string(&mut self) -> Result<Sexp, ParseError> {
80 self.bump(); let mut result = String::new();
82
83 while let Some(c) = self.current {
84 match c {
85 '"' => {
86 self.bump(); return Ok(Sexp::Atom(Atom::Q(result)));
88 }
89 _ => {
90 result.push(c);
91 self.bump();
92 }
93 }
94 }
95
96 Err(ParseError::UnclosedString)
97 }
98
99 fn parse_atom(&mut self) -> Result<Sexp, ParseError> {
100 let mut s = String::new();
101
102 if self.current == Some('-') {
103 s.push('-');
104 self.bump();
105 }
106
107 while let Some(c) = self.current {
108 if !c.is_whitespace() && c != '(' && c != ')' && c != '"' {
109 s.push(c);
110 self.bump();
111 } else {
112 break;
113 }
114 }
115
116 if s.is_empty() {
117 return Err(ParseError::InvalidToken("Empty atom".to_string()));
118 }
119
120 match s.as_str() {
121 "true" => Ok(Sexp::Atom(Atom::B(true))),
122 "false" => Ok(Sexp::Atom(Atom::B(false))),
123 _ => {
124 if let Ok(i) = s.parse::<i32>() {
125 Ok(Sexp::Atom(Atom::I(i)))
126 } else if let Ok(f) = s.parse::<f32>() {
127 Ok(Sexp::Atom(Atom::F(f)))
128 } else {
129 Ok(Sexp::Atom(Atom::S(s)))
130 }
131 }
132 }
133 }
134
135 pub fn parse_all(&mut self) -> Result<Vec<Sexp>, ParseError> {
136 let mut expressions = Vec::new();
137
138 while self.current.is_some() {
139 self.skip_whitespace();
140 if self.current.is_none() {
141 break;
142 }
143
144 let expr = self.parse()?;
145 expressions.push(expr);
146 }
147
148 Ok(expressions)
149 }
150}