1use std::str::Chars;
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum Atom {
5 S(String),
6 Q(String),
7 I(u128),
8 F(f64),
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_at_var(),
54 Some(_) => self.parse_atom(),
55 None => Err(ParseError::UnexpectedEOF),
56 }
57 }
58
59 fn parse_list(&mut self) -> Result<Sexp, ParseError> {
60 self.bump(); let mut items = Vec::new();
62
63 loop {
64 self.skip_whitespace();
65 match self.current {
66 Some(')') => {
67 self.bump(); break;
69 }
70 Some(_) => {
71 let expr = self.parse()?;
72 items.push(expr);
73 }
74 None => return Err(ParseError::UnexpectedEOF),
75 }
76 }
77 Ok(Sexp::List(items))
78 }
79
80 fn parse_at_var(&mut self) -> Result<Sexp, ParseError> {
81 let mut result = String::new();
82 while let Some(c) = self.current {
83 match c {
84 ')' => {
85 result.push(c);
86 self.bump();
87 return Ok(Sexp::Atom(Atom::S(result)));
88 }
89 _ => {
90 result.push(c);
91 self.bump();
92 }
93 }
94 }
95
96 Err(ParseError::UnclosedString)
97 }
98
99 fn parse_quoted_string(&mut self) -> Result<Sexp, ParseError> {
100 self.bump(); let mut result = String::new();
102
103 while let Some(c) = self.current {
104 match c {
105 '"' => {
106 self.bump(); return Ok(Sexp::Atom(Atom::Q(result)));
108 }
109 _ => {
110 result.push(c);
111 self.bump();
112 }
113 }
114 }
115
116 Err(ParseError::UnclosedString)
117 }
118
119 fn parse_atom(&mut self) -> Result<Sexp, ParseError> {
120 let mut s = String::new();
121
122 if self.current == Some('-') {
123 s.push('-');
124 self.bump();
125 }
126
127 while let Some(c) = self.current {
128 if !c.is_whitespace() && c != '(' && c != ')' && c != '"' {
129 s.push(c);
130 self.bump();
131 } else {
132 break;
133 }
134 }
135
136 if s.is_empty() {
137 return Err(ParseError::InvalidToken("Empty atom".to_string()));
138 }
139
140 match s.as_str() {
141 "true" => Ok(Sexp::Atom(Atom::B(true))),
142 "false" => Ok(Sexp::Atom(Atom::B(false))),
143 _ => {
144 if let Ok(i) = s.parse::<u128>() {
145 Ok(Sexp::Atom(Atom::I(i)))
146 } else if let Ok(f) = s.parse::<f64>() {
147 Ok(Sexp::Atom(Atom::F(f)))
148 } else {
149 Ok(Sexp::Atom(Atom::S(s)))
150 }
151 }
152 }
153 }
154
155 pub fn parse_all(&mut self) -> Result<Vec<Sexp>, ParseError> {
156 let mut expressions = Vec::new();
157
158 while self.current.is_some() {
159 self.skip_whitespace();
160 if self.current.is_none() {
161 break;
162 }
163
164 let expr = self.parse()?;
165 expressions.push(expr);
166 }
167
168 Ok(expressions)
169 }
170}