strata/
parser.rs

1use crate::error::{ParseError, ParseErrorKind};
2use crate::lexer::{Lexer, Token, TokenKind};
3use crate::value::Value;
4use std::collections::BTreeMap;
5
6pub struct Parser<'a> {
7    lexer: Lexer<'a>,
8    lookahead: Token,
9}
10
11impl<'a> Parser<'a> {
12    pub fn new(input: &'a str) -> Result<Self, ParseError> {
13        let mut lexer = Lexer::new(input);
14        let lookahead = lexer.next_token()?;
15
16        Ok(Self { lexer, lookahead })
17    }
18
19    fn advance(&mut self) -> Result<(), ParseError> {
20        self.lookahead = self.lexer.next_token()?;
21        Ok(())
22    }
23
24    fn expect(&mut self, kind: TokenKind) -> Result<(), ParseError> {
25        if self.lookahead.kind == kind {
26            self.advance()
27        } else {
28            Err(ParseError {
29                kind: ParseErrorKind::UnexpectedToken {
30                    expected: "different token",
31                    found: "unexpected token",
32                },
33                span: self.lookahead.span,
34            })
35        }
36    }
37
38    fn parse_list(&mut self) -> Result<Value, ParseError> {
39        self.expect(TokenKind::LBracket)?;
40
41        let mut items = Vec::new();
42
43        // empty list
44        if self.lookahead.kind == TokenKind::RBracket {
45            self.advance()?; // consume ']'
46            return Ok(Value::List(items));
47        }
48
49        loop {
50            // parse value
51            let element = self.parse_value()?;
52            items.push(element);
53
54            match self.lookahead.kind {
55                TokenKind::Comma => {
56                    self.advance()?; // consume ','
57
58                    // allow trailing comma
59                    if self.lookahead.kind == TokenKind::RBracket {
60                        break;
61                    }
62                }
63
64                TokenKind::RBracket => break,
65
66                _ => {
67                    return Err(ParseError {
68                        kind: ParseErrorKind::UnexpectedToken {
69                            expected: "',' or ']'",
70                            found: "token",
71                        },
72                        span: self.lookahead.span,
73                    });
74                }
75            }
76        }
77
78        self.expect(TokenKind::RBracket)?;
79        Ok(Value::List(items))
80    }
81
82    fn parse_map(&mut self) -> Result<Value, ParseError> {
83        self.expect(TokenKind::LBrace)?;
84
85        let mut map = BTreeMap::new();
86
87        // empty map
88        if self.lookahead.kind == TokenKind::RBrace {
89            self.advance()?; // consume '}'
90            return Ok(Value::Map(map));
91        }
92
93        loop {
94            // key must be identifier
95            let key = match &self.lookahead.kind {
96                TokenKind::Ident(name) => {
97                    let key = name.clone();
98                    self.advance()?;
99                    key
100                }
101
102                _ => {
103                    return Err(ParseError {
104                        kind: ParseErrorKind::UnexpectedToken {
105                            expected: "identifier",
106                            found: "token",
107                        },
108                        span: self.lookahead.span,
109                    });
110                }
111            };
112
113            let value = if self.lookahead.kind == TokenKind::LBrace {
114                // shorthand entry: key { ... }
115                self.parse_map()?
116            } else {
117                // normal entry: key : value
118                self.expect(TokenKind::Colon)?;
119                self.parse_value()?
120            };
121
122            map.insert(key, value);
123
124            match self.lookahead.kind {
125                TokenKind::Comma => {
126                    self.advance()?;
127
128                    // allow trailing comma
129                    if self.lookahead.kind == TokenKind::RBrace {
130                        break;
131                    }
132                }
133
134                TokenKind::RBrace => break,
135
136                TokenKind::Ident(_) => {
137                    // implicit separator via newline
138                    continue;
139                }
140
141                _ => {
142                    return Err(ParseError {
143                        kind: ParseErrorKind::UnexpectedToken {
144                            expected: "',' or '}'",
145                            found: "token",
146                        },
147                        span: self.lookahead.span,
148                    });
149                }
150            }
151        }
152
153        self.expect(TokenKind::RBrace)?;
154        Ok(Value::Map(map))
155    }
156
157    fn parse_value(&mut self) -> Result<Value, ParseError> {
158        match &self.lookahead.kind {
159            TokenKind::Null => {
160                self.advance()?;
161                Ok(Value::Null)
162            }
163
164            TokenKind::True => {
165                self.advance()?;
166                Ok(Value::Bool(true))
167            }
168
169            TokenKind::False => {
170                self.advance()?;
171                Ok(Value::Bool(false))
172            }
173
174            TokenKind::Int(number) => {
175                let v = *number;
176                self.advance()?;
177                Ok(Value::Int(v))
178            }
179
180            TokenKind::String(string) => {
181                let v = string.clone();
182                self.advance()?;
183                Ok(Value::String(v))
184            }
185
186            TokenKind::Bytes(bytes) => {
187                let v = bytes.clone();
188                self.advance()?;
189                Ok(Value::Bytes(v))
190            }
191
192            TokenKind::LBracket => self.parse_list(),
193            TokenKind::LBrace => self.parse_map(),
194
195            TokenKind::Ident(name) => {
196                let key = name.clone();
197                self.advance()?;
198
199                // identifier followed by '{' -> shorthand
200                if self.lookahead.kind == TokenKind::LBrace {
201                    let inner = self.parse_map()?;
202                    let mut map = BTreeMap::new();
203                    map.insert(key, inner);
204                    Ok(Value::Map(map))
205                } else {
206                    Err(ParseError {
207                        kind: ParseErrorKind::UnexpectedToken {
208                            expected: "map or value",
209                            found: "identifier",
210                        },
211                        span: self.lookahead.span,
212                    })
213                }
214            }
215
216            _ => Err(ParseError {
217                kind: ParseErrorKind::UnexpectedToken {
218                    expected: "value",
219                    found: "token",
220                },
221                span: self.lookahead.span,
222            }),
223        }
224    }
225}
226
227pub fn parse(input: &str) -> Result<Value, ParseError> {
228    let mut parser = Parser::new(input)?;
229    let parsed_value = parser.parse_value()?;
230
231    if parser.lookahead.kind != TokenKind::EOF {
232        return Err(ParseError {
233            kind: ParseErrorKind::UnexpectedToken {
234                expected: "EOF",
235                found: "extra input",
236            },
237            span: parser.lookahead.span,
238        });
239    }
240
241    Ok(parsed_value)
242}