rs_jsonnet/
parser.rs

1//! Parser for Jsonnet AST
2
3use crate::ast::{BinaryOp, Expr, Stmt, StringPart, UnaryOp};
4use crate::error::{JsonnetError, Result};
5use crate::lexer::Token;
6
7/// Parser for Jsonnet source code
8pub struct Parser {
9    tokens: Vec<Token>,
10    position: usize,
11}
12
13impl Parser {
14    /// Create a new parser
15    pub fn new(tokens: Vec<Token>) -> Self {
16        Self {
17            tokens,
18            position: 0,
19        }
20    }
21
22    /// Get the current token
23    fn current(&self) -> Option<&Token> {
24        self.tokens.get(self.position)
25    }
26
27    /// Advance to the next token
28    fn advance(&mut self) {
29        self.position += 1;
30    }
31
32    /// Parse the tokens into an AST
33    pub fn parse(&mut self) -> Result<Expr> {
34        // Parse semicolon-separated expressions, return the last one
35        let mut expr = self.parse_expression()?;
36
37        while matches!(self.current(), Some(Token::Semicolon)) {
38            self.advance(); // consume ';'
39            if matches!(self.current(), Some(Token::Eof)) {
40                break; // trailing semicolon is ok
41            }
42            expr = self.parse_expression()?;
43        }
44
45        if !matches!(self.current(), Some(Token::Eof)) {
46            return Err(JsonnetError::parse_error(
47                0, 0, // TODO: track line/column properly
48                "Unexpected tokens after expression"
49            ));
50        }
51        Ok(expr)
52    }
53
54    /// Parse an expression with precedence
55    fn parse_expression(&mut self) -> Result<Expr> {
56        self.parse_local()
57    }
58
59    /// Parse local variable bindings
60    fn parse_local(&mut self) -> Result<Expr> {
61        if matches!(self.current(), Some(Token::Local)) {
62            self.advance(); // consume 'local'
63
64            let mut bindings = Vec::new();
65
66            loop {
67                // Parse variable name
68                let name = match self.current().cloned() {
69                    Some(Token::Identifier(id)) => {
70                        self.advance();
71                        id
72                    }
73                    _ => return Err(JsonnetError::parse_error(0, 0, "Expected variable name after 'local'")),
74                };
75
76                self.expect_token(Token::Equal)?;
77                let value = self.parse_expression()?;
78                bindings.push((name, value));
79
80                // Check for comma (multiple bindings) or semicolon (end of bindings)
81                if matches!(self.current(), Some(Token::Comma)) {
82                    self.advance(); // consume ','
83                } else {
84                    break;
85                }
86            }
87
88            self.expect_token(Token::Semicolon)?;
89            let body = self.parse_expression()?;
90
91            Ok(Expr::Local(bindings, Box::new(body)))
92        } else {
93            self.parse_conditional()
94        }
95    }
96
97    /// Parse conditional expressions (if then else)
98    fn parse_conditional(&mut self) -> Result<Expr> {
99        if matches!(self.current(), Some(Token::If)) {
100            self.advance(); // consume 'if'
101
102            let condition = self.parse_expression()?;
103
104            self.expect_token(Token::Then)?;
105            let then_branch = self.parse_expression()?;
106
107            self.expect_token(Token::Else)?;
108            let else_branch = self.parse_expression()?;
109
110            Ok(Expr::Conditional(
111                Box::new(condition),
112                Box::new(then_branch),
113                Box::new(else_branch),
114            ))
115        } else {
116            self.parse_or()
117        }
118    }
119
120    /// Parse or expressions (lowest precedence)
121    fn parse_or(&mut self) -> Result<Expr> {
122        let mut expr = self.parse_and()?;
123
124        while let Some(Token::Or) = self.current() {
125            self.advance();
126            let right = self.parse_and()?;
127            expr = Expr::BinaryOp(BinaryOp::Or, Box::new(expr), Box::new(right));
128        }
129
130        Ok(expr)
131    }
132
133    /// Parse and expressions
134    fn parse_and(&mut self) -> Result<Expr> {
135        let mut expr = self.parse_comparison()?;
136
137        while let Some(Token::And) = self.current() {
138            self.advance();
139            let right = self.parse_comparison()?;
140            expr = Expr::BinaryOp(BinaryOp::And, Box::new(expr), Box::new(right));
141        }
142
143        Ok(expr)
144    }
145
146    /// Parse comparison expressions
147    fn parse_comparison(&mut self) -> Result<Expr> {
148        let mut expr = self.parse_additive()?;
149
150        loop {
151            let op = match self.current() {
152                Some(Token::Equal) => BinaryOp::Eq,
153                Some(Token::NotEqual) => BinaryOp::Ne,
154                Some(Token::LessThan) => BinaryOp::Lt,
155                Some(Token::LessThanEqual) => BinaryOp::Le,
156                Some(Token::GreaterThan) => BinaryOp::Gt,
157                Some(Token::GreaterThanEqual) => BinaryOp::Ge,
158                _ => break,
159            };
160            self.advance();
161            let right = self.parse_additive()?;
162            expr = Expr::BinaryOp(op, Box::new(expr), Box::new(right));
163        }
164
165        Ok(expr)
166    }
167
168    /// Parse additive expressions (+, -)
169    fn parse_additive(&mut self) -> Result<Expr> {
170        let mut expr = self.parse_multiplicative()?;
171
172        loop {
173            let op = match self.current() {
174                Some(Token::Plus) => BinaryOp::Add,
175                Some(Token::Minus) => BinaryOp::Sub,
176                _ => break,
177            };
178            self.advance();
179            let right = self.parse_multiplicative()?;
180            expr = Expr::BinaryOp(op, Box::new(expr), Box::new(right));
181        }
182
183        Ok(expr)
184    }
185
186    /// Parse multiplicative expressions (*, /, %)
187    fn parse_multiplicative(&mut self) -> Result<Expr> {
188        let mut expr = self.parse_unary()?;
189
190        loop {
191            let op = match self.current() {
192                Some(Token::Star) => BinaryOp::Mul,
193                Some(Token::Slash) => BinaryOp::Div,
194                Some(Token::Percent) => BinaryOp::Mod,
195                _ => break,
196            };
197            self.advance();
198            let right = self.parse_unary()?;
199            expr = Expr::BinaryOp(op, Box::new(expr), Box::new(right));
200        }
201
202        Ok(expr)
203    }
204
205    /// Parse unary expressions
206    fn parse_unary(&mut self) -> Result<Expr> {
207        if let Some(Token::Minus) = self.current() {
208            self.advance();
209            let expr = self.parse_unary()?;
210            return Ok(Expr::UnaryOp(UnaryOp::Neg, Box::new(expr)));
211        }
212        if let Some(Token::Plus) = self.current() {
213            self.advance();
214            let expr = self.parse_unary()?;
215            return Ok(Expr::UnaryOp(UnaryOp::Plus, Box::new(expr)));
216        }
217        if let Some(Token::Not) = self.current() {
218            self.advance();
219            let expr = self.parse_unary()?;
220            return Ok(Expr::UnaryOp(UnaryOp::Not, Box::new(expr)));
221        }
222
223        self.parse_postfix()
224    }
225
226    /// Parse primary expressions (literals, identifiers, parentheses, objects, arrays)
227    fn parse_primary(&mut self) -> Result<Expr> {
228        match self.current().cloned() {
229            Some(Token::String(s)) => {
230                self.advance();
231                // Check if this string contains interpolation
232                if s.contains("%(") && s.contains(")s") {
233                    self.parse_string_interpolation(&s)
234                } else {
235                    Ok(Expr::String(s))
236                }
237            }
238            Some(Token::Number(n)) => {
239                self.advance();
240                Ok(Expr::Number(n))
241            }
242            Some(Token::Boolean(b)) => {
243                self.advance();
244                Ok(Expr::Boolean(b))
245            }
246            Some(Token::Null) => {
247                self.advance();
248                Ok(Expr::Null)
249            }
250            Some(Token::Identifier(id)) => {
251                self.advance();
252                Ok(Expr::Identifier(id))
253            }
254            Some(Token::LeftBrace) => self.parse_object(),
255            Some(Token::LeftBracket) => {
256                self.advance(); // consume '['
257                self.parse_array()
258            },
259            Some(Token::Function) => self.parse_function(),
260            Some(Token::LeftParen) => {
261                self.advance(); // consume '('
262                let expr = self.parse_expression()?;
263                self.expect_token(Token::RightParen)?;
264                Ok(expr)
265            }
266            _ => Err(JsonnetError::parse_error(0, 0, "Expected expression")),
267        }
268    }
269
270    /// Parse postfix expressions (primary + indexing/field access/function calls)
271    fn parse_postfix(&mut self) -> Result<Expr> {
272        let mut expr = self.parse_primary()?;
273
274        loop {
275            match self.current() {
276                Some(Token::LeftBracket) => {
277                    self.advance(); // consume '['
278                    let index = self.parse_expression()?;
279                    self.expect_token(Token::RightBracket)?;
280                    expr = Expr::ArrayAccess(Box::new(expr), Box::new(index));
281                }
282                Some(Token::Dot) => {
283                    self.advance(); // consume '.'
284                    match self.current().cloned() {
285                        Some(Token::Identifier(field)) => {
286                            self.advance();
287                            expr = Expr::FieldAccess(Box::new(expr), field);
288                        }
289                        _ => return Err(JsonnetError::parse_error(0, 0, "Expected field name after '.'")),
290                    }
291                }
292                Some(Token::LeftParen) => {
293                    // Function call
294                    self.advance(); // consume '('
295                    let mut args = Vec::new();
296
297                    if !matches!(self.current(), Some(Token::RightParen)) {
298                        loop {
299                            let arg = self.parse_expression()?;
300                            args.push(arg);
301
302                            if !matches!(self.current(), Some(Token::Comma)) {
303                                break;
304                            }
305                            self.advance(); // consume ','
306                        }
307                    }
308
309                    self.expect_token(Token::RightParen)?;
310                    expr = Expr::Call(Box::new(expr), args);
311                }
312                _ => break,
313            }
314        }
315
316        Ok(expr)
317    }
318
319    /// Parse object literal { key: value, ... }
320    fn parse_object(&mut self) -> Result<Expr> {
321        self.expect_token(Token::LeftBrace)?;
322        let mut fields = Vec::new();
323
324        if !matches!(self.current(), Some(Token::RightBrace)) {
325            loop {
326                // For now, only support string keys
327                let key = match self.current().cloned() {
328                    Some(Token::String(s)) => {
329                        self.advance();
330                        s
331                    }
332                    Some(Token::Identifier(id)) => {
333                        self.advance();
334                        id
335                    }
336                    _ => return Err(JsonnetError::parse_error(0, 0, "Expected object key")),
337                };
338
339                self.expect_token(Token::Colon)?;
340                let value = self.parse_expression()?;
341                fields.push((key, value));
342
343                if !matches!(self.current(), Some(Token::Comma)) {
344                    break;
345                }
346                self.advance(); // consume ','
347            }
348        }
349
350        self.expect_token(Token::RightBrace)?;
351        Ok(Expr::Object(fields))
352    }
353
354    /// Parse array literal [ expr, expr, ... ]
355    fn parse_array(&mut self) -> Result<Expr> {
356        // Note: LeftBracket is already consumed
357
358        if matches!(self.current(), Some(Token::RightBracket)) {
359            // Empty array
360            self.advance(); // consume ']'
361            return Ok(Expr::Array(Vec::new()));
362        }
363
364        // Parse first expression
365        let expr = self.parse_expression()?;
366
367        // Check if this is an array comprehension (next token is 'for')
368        if matches!(self.current(), Some(Token::For)) {
369            // Array comprehension
370            self.advance(); // consume 'for'
371            let var_name = match self.current().cloned() {
372                Some(Token::Identifier(name)) => {
373                    self.advance();
374                    name
375                }
376                _ => return Err(JsonnetError::parse_error(0, 0, "Expected variable name after 'for'")),
377            };
378
379            self.expect_token(Token::In)?;
380            let array_expr = self.parse_expression()?;
381
382            // Optional condition
383            let condition = if matches!(self.current(), Some(Token::If)) {
384                self.advance(); // consume 'if'
385                Some(Box::new(self.parse_expression()?))
386            } else {
387                None
388            };
389
390            self.expect_token(Token::RightBracket)?;
391
392            return Ok(Expr::ArrayComprehension {
393                expr: Box::new(expr),
394                var_name,
395                array_expr: Box::new(array_expr),
396                condition,
397            });
398        }
399
400        // Regular array - parse remaining elements
401        let mut elements = vec![expr];
402        while matches!(self.current(), Some(Token::Comma)) {
403            self.advance(); // consume ','
404            let expr = self.parse_expression()?;
405            elements.push(expr);
406        }
407
408        self.expect_token(Token::RightBracket)?;
409        Ok(Expr::Array(elements))
410    }
411
412
413    /// Parse function definition
414    fn parse_function(&mut self) -> Result<Expr> {
415        self.expect_token(Token::Function)?;
416
417        // Parse parameters
418        self.expect_token(Token::LeftParen)?;
419        let mut params = Vec::new();
420
421        if !matches!(self.current(), Some(Token::RightParen)) {
422            loop {
423                match self.current().cloned() {
424                    Some(Token::Identifier(param)) => {
425                        self.advance();
426                        params.push(param);
427                    }
428                    _ => return Err(JsonnetError::parse_error(0, 0, "Expected parameter name")),
429                }
430
431                if !matches!(self.current(), Some(Token::Comma)) {
432                    break;
433                }
434                self.advance(); // consume ','
435            }
436        }
437
438        self.expect_token(Token::RightParen)?;
439
440        // Parse function body
441        let body = self.parse_expression()?;
442
443        Ok(Expr::Function(params, Box::new(body)))
444    }
445
446    /// Parse string interpolation
447    fn parse_string_interpolation(&mut self, s: &str) -> Result<Expr> {
448        let mut parts = Vec::new();
449        let mut remaining = s;
450
451        while let Some(start) = remaining.find("%(") {
452            // Add literal part before interpolation
453            if start > 0 {
454                parts.push(StringPart::Literal(remaining[..start].to_string()));
455            }
456
457            // Find the closing )s
458            if let Some(end) = remaining[start..].find(")s") {
459                let var_part = &remaining[start + 2..start + end];
460                // For now, treat as identifier. In full implementation, this should be parsed as expression
461                parts.push(StringPart::Interpolation(Expr::Identifier(var_part.to_string())));
462                remaining = &remaining[start + end + 2..];
463            } else {
464                // Not a valid interpolation, treat rest as literal
465                parts.push(StringPart::Literal(remaining.to_string()));
466                break;
467            }
468        }
469
470        // Add remaining literal part
471        if !remaining.is_empty() {
472            parts.push(StringPart::Literal(remaining.to_string()));
473        }
474
475        if parts.is_empty() {
476            // No interpolation found, return as literal string
477            return Ok(Expr::String(s.to_string()));
478        }
479
480        Ok(Expr::StringInterpolation(parts))
481    }
482
483    /// Expect a specific token, advance if found
484    fn expect_token(&mut self, expected: Token) -> Result<()> {
485        match self.current() {
486            Some(token) if token == &expected => {
487                self.advance();
488                Ok(())
489            }
490            _ => Err(JsonnetError::parse_error(0, 0, format!("Expected {:?}", expected))),
491        }
492    }
493}
494
495impl Default for Parser {
496    fn default() -> Self {
497        Self::new(vec![])
498    }
499}