liquid_fixpoint/
sexp.rs

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(); // consume '('
61        let mut items = Vec::new();
62
63        loop {
64            self.skip_whitespace();
65            match self.current {
66                Some(')') => {
67                    self.bump(); // consume ')'
68                    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(); // consume '"'
101        let mut result = String::new();
102
103        while let Some(c) = self.current {
104            match c {
105                '"' => {
106                    self.bump(); // consume closing '"'
107                    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}