use oxabl_ast::{Expression, Identifier, Span};
use oxabl_lexer::{Kind, is_callable_kind};
use super::{ParseError, ParseResult, Parser};
use crate::literal::token_to_literal;
impl Parser<'_> {
pub fn parse_expression(&mut self) -> ParseResult<Expression> {
self.parse_ternary()
}
pub fn parse_ternary(&mut self) -> ParseResult<Expression> {
if !self.check(Kind::KwIf) {
return self.parse_or();
}
self.advance(); let condition = self.parse_or()?;
self.expect_kind(Kind::Then, "Expected 'THEN' after IF condition")?;
let then_expr = self.parse_ternary()?;
self.expect_kind(Kind::KwElse, "Expected 'ELSE' in IF expression")?;
let else_expr = self.parse_ternary()?;
Ok(Expression::IfThenElse(
Box::new(condition),
Box::new(then_expr),
Box::new(else_expr),
))
}
pub fn parse_or(&mut self) -> ParseResult<Expression> {
let mut expr = self.parse_and()?;
while self.check(Kind::Or) {
self.advance();
let right = self.parse_and()?;
expr = Expression::Or(Box::new(expr), Box::new(right));
}
Ok(expr)
}
pub fn parse_and(&mut self) -> ParseResult<Expression> {
let mut expr = self.parse_comparison()?;
while self.check(Kind::And) {
self.advance();
let right = self.parse_comparison()?;
expr = Expression::And(Box::new(expr), Box::new(right));
}
Ok(expr)
}
pub(super) fn is_comparison_operator(&self) -> bool {
matches!(
self.peek().kind,
Kind::Equals
| Kind::NotEqual
| Kind::LessThan
| Kind::LessThanOrEqual
| Kind::GreaterThan
| Kind::GreaterThanOrEqual
| Kind::Eq
| Kind::Ne
| Kind::Lt
| Kind::Le
| Kind::Gt
| Kind::Ge
| Kind::Begins
| Kind::Matches
| Kind::Contains
)
}
pub fn parse_comparison(&mut self) -> ParseResult<Expression> {
let left = self.parse_additive()?;
if !self.is_comparison_operator() {
return Ok(left);
}
let op_kind = self.advance().kind;
let right = self.parse_additive()?;
let expr = match op_kind {
Kind::Equals | Kind::Eq => Expression::Equal(Box::new(left), Box::new(right)),
Kind::NotEqual | Kind::Ne => Expression::NotEqual(Box::new(left), Box::new(right)),
Kind::LessThan | Kind::Lt => Expression::LessThan(Box::new(left), Box::new(right)),
Kind::LessThanOrEqual | Kind::Le => {
Expression::LessThanOrEqual(Box::new(left), Box::new(right))
}
Kind::GreaterThan | Kind::Gt => {
Expression::GreaterThan(Box::new(left), Box::new(right))
}
Kind::GreaterThanOrEqual | Kind::Ge => {
Expression::GreaterThanOrEqual(Box::new(left), Box::new(right))
}
Kind::Begins => Expression::Begins(Box::new(left), Box::new(right)),
Kind::Matches => Expression::Matches(Box::new(left), Box::new(right)),
Kind::Contains => Expression::Contains(Box::new(left), Box::new(right)),
_ => unreachable!(),
};
Ok(expr)
}
pub fn parse_additive(&mut self) -> ParseResult<Expression> {
let mut expr = self.parse_multiplicative()?;
while self.check(Kind::Add) || self.check(Kind::Minus) {
let operator = self.advance();
match operator.kind {
Kind::Add => {
let right_exp = self.parse_multiplicative()?;
expr = Expression::Add(Box::new(expr), Box::new(right_exp));
}
Kind::Minus => {
let right_exp = self.parse_multiplicative()?;
expr = Expression::Minus(Box::new(expr), Box::new(right_exp));
}
_ => unreachable!(),
}
}
Ok(expr)
}
pub fn parse_multiplicative(&mut self) -> ParseResult<Expression> {
let mut expr = self.parse_unary()?;
while self.check(Kind::Star) || self.check(Kind::Slash) || self.check(Kind::Modulo) {
let operator = self.advance();
match operator.kind {
Kind::Star => {
let right_exp = self.parse_unary()?;
expr = Expression::Multiply(Box::new(expr), Box::new(right_exp));
}
Kind::Slash => {
let right_exp = self.parse_unary()?;
expr = Expression::Divide(Box::new(expr), Box::new(right_exp));
}
Kind::Modulo => {
let right_exp = self.parse_unary()?;
expr = Expression::Modulo(Box::new(expr), Box::new(right_exp));
}
_ => unreachable!(),
}
}
Ok(expr)
}
pub fn parse_unary(&mut self) -> ParseResult<Expression> {
if self.check(Kind::Minus) {
self.advance();
let expr = self.parse_unary()?;
return Ok(Expression::Negate(Box::new(expr)));
}
if self.check(Kind::Not) {
self.advance();
let expr = self.parse_unary()?;
return Ok(Expression::Not(Box::new(expr)));
}
self.parse_postfix()
}
pub fn parse_postfix(&mut self) -> ParseResult<Expression> {
let mut expr = self.parse_primary()?;
if matches!(expr, Expression::Literal(_)) {
return Ok(expr);
}
loop {
if self.check(Kind::Colon) {
let next_is_member = self
.tokens
.get(self.current + 1)
.is_some_and(|t| is_callable_kind(t.kind));
if !next_is_member {
break;
}
expr = self.parse_member_or_method(expr)?;
} else if self.check(Kind::LeftBracket) {
expr = self.parse_array_access(expr)?;
} else if self.check(Kind::Period)
&& self.is_field_access_ahead()
&& Self::can_have_field_access(&expr)
{
expr = self.parse_field_access(expr)?;
} else {
break;
}
}
Ok(expr)
}
pub fn parse_member_or_method(&mut self, object: Expression) -> ParseResult<Expression> {
self.advance();
if !is_callable_kind(self.peek().kind) {
return Err(ParseError {
message: format!(
"Expected identifier after ':', found {:?}",
self.peek().kind
),
span: Span {
start: self.peek().start as u32,
end: self.peek().end as u32,
},
});
}
let token = self.advance().clone();
let member = Identifier {
span: Span {
start: token.start as u32,
end: token.end as u32,
},
name: self.source[token.start..token.end].to_string(),
};
if self.check(Kind::LeftParen) {
self.advance();
let mut arguments = Vec::new();
if !self.check(Kind::RightParen) {
arguments.push(self.parse_expression()?);
while self.check(Kind::Comma) {
self.advance(); arguments.push(self.parse_expression()?);
}
}
self.expect_kind(Kind::RightParen, "Expected ')' after method arguments")?;
return Ok(Expression::MethodCall {
object: Box::new(object),
method: member,
arguments,
});
}
Ok(Expression::MemberAccess {
object: Box::new(object),
member,
})
}
pub fn parse_array_access(&mut self, array: Expression) -> ParseResult<Expression> {
self.advance();
let index = self.parse_expression()?;
self.expect_kind(Kind::RightBracket, "Expected ']' after array index")?;
Ok(Expression::ArrayAccess {
array: Box::new(array),
index: Box::new(index),
})
}
pub fn is_field_access_ahead(&mut self) -> bool {
if !self.check(Kind::Period) {
return false;
}
self.tokens
.get(self.current + 1)
.is_some_and(|t| t.kind == Kind::Identifier)
}
fn can_have_field_access(expr: &Expression) -> bool {
matches!(
expr,
Expression::Identifier(_) | Expression::FieldAccess { .. }
)
}
pub fn parse_field_access(&mut self, qualifier: Expression) -> ParseResult<Expression> {
self.advance();
if !self.check(Kind::Identifier) {
return Err(ParseError {
message: "Expected field name after '.'".to_string(),
span: Span {
start: self.peek().start as u32,
end: self.peek().end as u32,
},
});
}
let token = self.advance().clone();
let field = Identifier {
span: Span {
start: token.start as u32,
end: token.end as u32,
},
name: self.source[token.start..token.end].to_string(),
};
Ok(Expression::FieldAccess {
qualifier: Box::new(qualifier),
field,
})
}
pub fn parse_primary(&mut self) -> ParseResult<Expression> {
if self.check(Kind::LeftParen) {
self.advance();
let expr = self.parse_expression()?;
self.expect_kind(Kind::RightParen, "Expected ')' after expression")?;
return Ok(expr);
}
if self.check(Kind::IntegerLiteral)
|| self.check(Kind::DecimalLiteral)
|| self.check(Kind::StringLiteral)
|| self.check(Kind::KwTrue)
|| self.check(Kind::KwFalse)
|| self.check(Kind::Question)
{
let token = self.advance();
let literal = token_to_literal(token).ok_or_else(|| ParseError {
message: "Failed to convert token to literal".to_string(),
span: Span {
start: token.start as u32,
end: token.end as u32,
},
})?;
return Ok(Expression::Literal(literal));
}
if is_callable_kind(self.peek().kind) {
let token = self.advance();
let start = token.start;
let end = token.end;
let name = self.source[start..end].to_string();
let identifier = Identifier {
span: Span {
start: start as u32,
end: end as u32,
},
name,
};
if self.check(Kind::LeftParen) {
return self.parse_function_call(identifier);
}
return Ok(Expression::Identifier(identifier));
}
Err(ParseError {
message: format!("Unexpected token {:?}", self.peek().kind),
span: Span {
start: self.peek().start as u32,
end: self.peek().end as u32,
},
})
}
pub fn parse_function_call(&mut self, name: Identifier) -> ParseResult<Expression> {
self.advance();
let mut arguments = Vec::new();
if !self.check(Kind::RightParen) {
arguments.push(self.parse_expression()?);
while self.check(Kind::Comma) {
self.advance(); arguments.push(self.parse_expression()?);
}
}
self.expect_kind(Kind::RightParen, "Expected ')' after function arguments")?;
Ok(Expression::FunctionCall { name, arguments })
}
}