use crate::ast::{BinaryOp, Expr, Stmt, StringPart, UnaryOp};
use crate::error::{JsonnetError, Result};
use crate::lexer::Token;
pub struct Parser {
tokens: Vec<Token>,
position: usize,
}
impl Parser {
pub fn new(tokens: Vec<Token>) -> Self {
Self {
tokens,
position: 0,
}
}
fn current(&self) -> Option<&Token> {
self.tokens.get(self.position)
}
fn advance(&mut self) {
self.position += 1;
}
pub fn parse(&mut self) -> Result<Expr> {
let mut expr = self.parse_expression()?;
while matches!(self.current(), Some(Token::Semicolon)) {
self.advance(); if matches!(self.current(), Some(Token::Eof)) {
break; }
expr = self.parse_expression()?;
}
if !matches!(self.current(), Some(Token::Eof)) {
return Err(JsonnetError::parse_error(
0, 0, "Unexpected tokens after expression"
));
}
Ok(expr)
}
fn parse_expression(&mut self) -> Result<Expr> {
self.parse_local()
}
fn parse_local(&mut self) -> Result<Expr> {
if matches!(self.current(), Some(Token::Local)) {
self.advance();
let mut bindings = Vec::new();
loop {
let name = match self.current().cloned() {
Some(Token::Identifier(id)) => {
self.advance();
id
}
_ => return Err(JsonnetError::parse_error(0, 0, "Expected variable name after 'local'")),
};
self.expect_token(Token::Equal)?;
let value = self.parse_expression()?;
bindings.push((name, value));
if matches!(self.current(), Some(Token::Comma)) {
self.advance(); } else {
break;
}
}
self.expect_token(Token::Semicolon)?;
let body = self.parse_expression()?;
Ok(Expr::Local(bindings, Box::new(body)))
} else {
self.parse_conditional()
}
}
fn parse_conditional(&mut self) -> Result<Expr> {
if matches!(self.current(), Some(Token::If)) {
self.advance();
let condition = self.parse_expression()?;
self.expect_token(Token::Then)?;
let then_branch = self.parse_expression()?;
self.expect_token(Token::Else)?;
let else_branch = self.parse_expression()?;
Ok(Expr::Conditional(
Box::new(condition),
Box::new(then_branch),
Box::new(else_branch),
))
} else {
self.parse_or()
}
}
fn parse_or(&mut self) -> Result<Expr> {
let mut expr = self.parse_and()?;
while let Some(Token::Or) = self.current() {
self.advance();
let right = self.parse_and()?;
expr = Expr::BinaryOp(BinaryOp::Or, Box::new(expr), Box::new(right));
}
Ok(expr)
}
fn parse_and(&mut self) -> Result<Expr> {
let mut expr = self.parse_comparison()?;
while let Some(Token::And) = self.current() {
self.advance();
let right = self.parse_comparison()?;
expr = Expr::BinaryOp(BinaryOp::And, Box::new(expr), Box::new(right));
}
Ok(expr)
}
fn parse_comparison(&mut self) -> Result<Expr> {
let mut expr = self.parse_additive()?;
loop {
let op = match self.current() {
Some(Token::Equal) => BinaryOp::Eq,
Some(Token::NotEqual) => BinaryOp::Ne,
Some(Token::LessThan) => BinaryOp::Lt,
Some(Token::LessThanEqual) => BinaryOp::Le,
Some(Token::GreaterThan) => BinaryOp::Gt,
Some(Token::GreaterThanEqual) => BinaryOp::Ge,
_ => break,
};
self.advance();
let right = self.parse_additive()?;
expr = Expr::BinaryOp(op, Box::new(expr), Box::new(right));
}
Ok(expr)
}
fn parse_additive(&mut self) -> Result<Expr> {
let mut expr = self.parse_multiplicative()?;
loop {
let op = match self.current() {
Some(Token::Plus) => BinaryOp::Add,
Some(Token::Minus) => BinaryOp::Sub,
_ => break,
};
self.advance();
let right = self.parse_multiplicative()?;
expr = Expr::BinaryOp(op, Box::new(expr), Box::new(right));
}
Ok(expr)
}
fn parse_multiplicative(&mut self) -> Result<Expr> {
let mut expr = self.parse_unary()?;
loop {
let op = match self.current() {
Some(Token::Star) => BinaryOp::Mul,
Some(Token::Slash) => BinaryOp::Div,
Some(Token::Percent) => BinaryOp::Mod,
_ => break,
};
self.advance();
let right = self.parse_unary()?;
expr = Expr::BinaryOp(op, Box::new(expr), Box::new(right));
}
Ok(expr)
}
fn parse_unary(&mut self) -> Result<Expr> {
if let Some(Token::Minus) = self.current() {
self.advance();
let expr = self.parse_unary()?;
return Ok(Expr::UnaryOp(UnaryOp::Neg, Box::new(expr)));
}
if let Some(Token::Plus) = self.current() {
self.advance();
let expr = self.parse_unary()?;
return Ok(Expr::UnaryOp(UnaryOp::Plus, Box::new(expr)));
}
if let Some(Token::Not) = self.current() {
self.advance();
let expr = self.parse_unary()?;
return Ok(Expr::UnaryOp(UnaryOp::Not, Box::new(expr)));
}
self.parse_postfix()
}
fn parse_primary(&mut self) -> Result<Expr> {
match self.current().cloned() {
Some(Token::String(s)) => {
self.advance();
if s.contains("%(") && s.contains(")s") {
self.parse_string_interpolation(&s)
} else {
Ok(Expr::String(s))
}
}
Some(Token::Number(n)) => {
self.advance();
Ok(Expr::Number(n))
}
Some(Token::Boolean(b)) => {
self.advance();
Ok(Expr::Boolean(b))
}
Some(Token::Null) => {
self.advance();
Ok(Expr::Null)
}
Some(Token::Identifier(id)) => {
self.advance();
Ok(Expr::Identifier(id))
}
Some(Token::LeftBrace) => self.parse_object(),
Some(Token::LeftBracket) => {
self.advance(); self.parse_array()
},
Some(Token::Function) => self.parse_function(),
Some(Token::LeftParen) => {
self.advance(); let expr = self.parse_expression()?;
self.expect_token(Token::RightParen)?;
Ok(expr)
}
_ => Err(JsonnetError::parse_error(0, 0, "Expected expression")),
}
}
fn parse_postfix(&mut self) -> Result<Expr> {
let mut expr = self.parse_primary()?;
loop {
match self.current() {
Some(Token::LeftBracket) => {
self.advance(); let index = self.parse_expression()?;
self.expect_token(Token::RightBracket)?;
expr = Expr::ArrayAccess(Box::new(expr), Box::new(index));
}
Some(Token::Dot) => {
self.advance(); match self.current().cloned() {
Some(Token::Identifier(field)) => {
self.advance();
expr = Expr::FieldAccess(Box::new(expr), field);
}
_ => return Err(JsonnetError::parse_error(0, 0, "Expected field name after '.'")),
}
}
Some(Token::LeftParen) => {
self.advance(); let mut args = Vec::new();
if !matches!(self.current(), Some(Token::RightParen)) {
loop {
let arg = self.parse_expression()?;
args.push(arg);
if !matches!(self.current(), Some(Token::Comma)) {
break;
}
self.advance(); }
}
self.expect_token(Token::RightParen)?;
expr = Expr::Call(Box::new(expr), args);
}
_ => break,
}
}
Ok(expr)
}
fn parse_object(&mut self) -> Result<Expr> {
self.expect_token(Token::LeftBrace)?;
let mut fields = Vec::new();
if !matches!(self.current(), Some(Token::RightBrace)) {
loop {
let key = match self.current().cloned() {
Some(Token::String(s)) => {
self.advance();
s
}
Some(Token::Identifier(id)) => {
self.advance();
id
}
_ => return Err(JsonnetError::parse_error(0, 0, "Expected object key")),
};
self.expect_token(Token::Colon)?;
let value = self.parse_expression()?;
fields.push((key, value));
if !matches!(self.current(), Some(Token::Comma)) {
break;
}
self.advance(); }
}
self.expect_token(Token::RightBrace)?;
Ok(Expr::Object(fields))
}
fn parse_array(&mut self) -> Result<Expr> {
if matches!(self.current(), Some(Token::RightBracket)) {
self.advance(); return Ok(Expr::Array(Vec::new()));
}
let expr = self.parse_expression()?;
if matches!(self.current(), Some(Token::For)) {
self.advance(); let var_name = match self.current().cloned() {
Some(Token::Identifier(name)) => {
self.advance();
name
}
_ => return Err(JsonnetError::parse_error(0, 0, "Expected variable name after 'for'")),
};
self.expect_token(Token::In)?;
let array_expr = self.parse_expression()?;
let condition = if matches!(self.current(), Some(Token::If)) {
self.advance(); Some(Box::new(self.parse_expression()?))
} else {
None
};
self.expect_token(Token::RightBracket)?;
return Ok(Expr::ArrayComprehension {
expr: Box::new(expr),
var_name,
array_expr: Box::new(array_expr),
condition,
});
}
let mut elements = vec![expr];
while matches!(self.current(), Some(Token::Comma)) {
self.advance(); let expr = self.parse_expression()?;
elements.push(expr);
}
self.expect_token(Token::RightBracket)?;
Ok(Expr::Array(elements))
}
fn parse_function(&mut self) -> Result<Expr> {
self.expect_token(Token::Function)?;
self.expect_token(Token::LeftParen)?;
let mut params = Vec::new();
if !matches!(self.current(), Some(Token::RightParen)) {
loop {
match self.current().cloned() {
Some(Token::Identifier(param)) => {
self.advance();
params.push(param);
}
_ => return Err(JsonnetError::parse_error(0, 0, "Expected parameter name")),
}
if !matches!(self.current(), Some(Token::Comma)) {
break;
}
self.advance(); }
}
self.expect_token(Token::RightParen)?;
let body = self.parse_expression()?;
Ok(Expr::Function(params, Box::new(body)))
}
fn parse_string_interpolation(&mut self, s: &str) -> Result<Expr> {
let mut parts = Vec::new();
let mut remaining = s;
while let Some(start) = remaining.find("%(") {
if start > 0 {
parts.push(StringPart::Literal(remaining[..start].to_string()));
}
if let Some(end) = remaining[start..].find(")s") {
let var_part = &remaining[start + 2..start + end];
parts.push(StringPart::Interpolation(Expr::Identifier(var_part.to_string())));
remaining = &remaining[start + end + 2..];
} else {
parts.push(StringPart::Literal(remaining.to_string()));
break;
}
}
if !remaining.is_empty() {
parts.push(StringPart::Literal(remaining.to_string()));
}
if parts.is_empty() {
return Ok(Expr::String(s.to_string()));
}
Ok(Expr::StringInterpolation(parts))
}
fn expect_token(&mut self, expected: Token) -> Result<()> {
match self.current() {
Some(token) if token == &expected => {
self.advance();
Ok(())
}
_ => Err(JsonnetError::parse_error(0, 0, format!("Expected {:?}", expected))),
}
}
}
impl Default for Parser {
fn default() -> Self {
Self::new(vec![])
}
}