use crate::parser::ast::Expr;
use crate::parser::lexer::{Token, TokenKind};
use super::utils::Parser;
use super::primary::parse_primary;
fn pos(parser: &Parser) -> (usize, usize) {
parser.current().map(|t| (t.line, t.col)).unwrap_or((0, 0))
}
pub fn parse_ternary(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_pipe(parser)?;
while let Some(Token { kind: TokenKind::Question, .. }) = parser.current() {
parser.advance();
let if_true = parse_expression(parser)?;
parser.expect(&TokenKind::Colon)?;
let if_false = parse_expression(parser)?;
expr = Expr::Ternary {
cond: Box::new(expr),
if_true: Box::new(if_true),
if_false: Box::new(if_false),
line,
col,
};
}
Ok(expr)
}
pub fn parse_pipe(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_xor(parser)?;
loop {
match parser.current() {
Some(Token { kind: TokenKind::Pipe, .. }) => {
parser.advance();
let right = parse_xor(parser)?;
expr = Expr::BitOr {
left: Box::new(expr),
right: Box::new(right),
line,
col,
};
}
_ => break,
}
}
Ok(expr)
}
pub fn parse_xor(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_tilde(parser)?;
loop {
match parser.current() {
Some(Token { kind: TokenKind::Caret, .. }) => {
parser.advance();
let right = parse_tilde(parser)?;
expr = Expr::BitXor {
left: Box::new(expr),
right: Box::new(right),
line,
col,
};
}
_ => break,
}
}
Ok(expr)
}
pub fn parse_tilde(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_or(parser)?;
loop {
match parser.current() {
Some(Token { kind: TokenKind::Tilde, .. }) => {
parser.advance();
let right = parse_or(parser)?;
expr = Expr::BitTilde {
left: Box::new(expr),
right: Box::new(right),
line,
col,
};
}
_ => break,
}
}
Ok(expr)
}
pub fn parse_or(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_and(parser)?;
loop {
match parser.current() {
Some(Token { kind: TokenKind::OrOr, .. }) => {
parser.advance();
let right = parse_and(parser)?;
expr = Expr::OrOr {
left: Box::new(expr),
right: Box::new(right),
line,
col,
};
}
_ => break,
}
}
Ok(expr)
}
pub fn parse_and(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_bitand(parser)?;
loop {
match parser.current() {
Some(Token { kind: TokenKind::AndAnd, .. }) => {
parser.advance();
let right = parse_bitand(parser)?;
expr = Expr::AndAnd {
left: Box::new(expr),
right: Box::new(right),
line,
col,
};
}
_ => break,
}
}
Ok(expr)
}
pub fn parse_bitand(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_shifts(parser)?;
loop {
match parser.current() {
Some(Token { kind: TokenKind::Amp, .. }) => {
parser.advance();
let right = parse_shifts(parser)?;
expr = Expr::BitAnd {
left: Box::new(expr),
right: Box::new(right),
line,
col,
};
}
_ => break,
}
}
Ok(expr)
}
pub fn parse_shifts(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_comparison(parser)?;
loop {
match parser.current() {
Some(Token { kind: TokenKind::Shl, .. }) => {
parser.advance();
let right = parse_comparison(parser)?;
expr = Expr::Shl {
left: Box::new(expr),
right: Box::new(right),
line,
col,
};
}
Some(Token { kind: TokenKind::Shr, .. }) => {
parser.advance();
let right = parse_comparison(parser)?;
expr = Expr::Shr {
left: Box::new(expr),
right: Box::new(right),
line,
col,
};
}
_ => break,
}
}
Ok(expr)
}
pub fn parse_comparison(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_term(parser)?;
loop {
let op = match parser.current() {
Some(Token { kind: TokenKind::Gt, .. }) => { parser.advance(); ">" }
Some(Token { kind: TokenKind::Lt, .. }) => { parser.advance(); "<" }
Some(Token { kind: TokenKind::EqEq, .. }) => { parser.advance(); "==" }
Some(Token { kind: TokenKind::Le, .. }) => { parser.advance(); "<=" }
Some(Token { kind: TokenKind::Ge, .. }) => { parser.advance(); ">=" }
Some(Token { kind: TokenKind::Ne, .. }) => { parser.advance(); "!=" }
_ => break,
};
let right = parse_term(parser)?;
expr = match op {
">" => Expr::Gt { left: Box::new(expr), right: Box::new(right), line, col },
"<" => Expr::Lt { left: Box::new(expr), right: Box::new(right), line, col },
"==" => Expr::EqEq { left: Box::new(expr), right: Box::new(right), line, col },
"<=" => Expr::Le { left: Box::new(expr), right: Box::new(right), line, col },
">=" => Expr::Ge { left: Box::new(expr), right: Box::new(right), line, col },
"!=" => Expr::Ne { left: Box::new(expr), right: Box::new(right), line, col },
_ => unreachable!(),
};
}
Ok(expr)
}
pub fn parse_term(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_factor(parser)?;
loop {
let op = match parser.current() {
Some(Token { kind: TokenKind::Plus, .. }) => { parser.advance(); "+" }
Some(Token { kind: TokenKind::Minus, .. }) => { parser.advance(); "-" }
_ => break,
};
let right = parse_factor(parser)?;
expr = match op {
"+" => Expr::Add { left: Box::new(expr), right: Box::new(right), line, col },
"-" => Expr::Sub { left: Box::new(expr), right: Box::new(right), line, col },
_ => unreachable!(),
};
}
Ok(expr)
}
pub fn parse_factor(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_postfix(parser)?;
loop {
let op = match parser.current() {
Some(Token { kind: TokenKind::Star, .. }) => { parser.advance(); "*" }
Some(Token { kind: TokenKind::Slash, .. }) => { parser.advance(); "/" }
Some(Token { kind: TokenKind::Percent, .. }) => { parser.advance(); "%" }
_ => break,
};
let right = parse_postfix(parser)?;
expr = match op {
"*" => Expr::Mul { left: Box::new(expr), right: Box::new(right), line, col },
"/" => Expr::Div { left: Box::new(expr), right: Box::new(right), line, col },
"%" => Expr::Mod { left: Box::new(expr), right: Box::new(right), line, col },
_ => unreachable!(),
};
}
Ok(expr)
}
pub fn parse_postfix(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
let (line, col) = pos(parser);
let mut expr = parse_primary(parser)?;
loop {
if let Some(Token { kind: TokenKind::LParen, .. }) = parser.current() {
parser.advance();
let mut args = Vec::new();
if let Some(Token { kind: TokenKind::RParen, .. }) = parser.current() {
parser.advance();
} else {
args.push(parse_expression(parser)?);
while let Some(Token { kind: TokenKind::Comma, .. }) = parser.current() {
parser.advance();
args.push(parse_expression(parser)?);
}
parser.expect(&TokenKind::RParen)?;
}
expr = Expr::FunctionCall {
callee: Box::new(expr),
args,
line,
col,
};
} else if let Some(Token { kind: TokenKind::LBracket, .. }) = parser.current() {
parser.advance();
let idx = parse_expression(parser)?;
parser.expect(&TokenKind::RBracket)?;
expr = Expr::Index {
base: Box::new(expr),
index: Box::new(idx),
line,
col,
};
} else {
break;
}
}
Ok(expr)
}
pub fn parse_expression(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
parse_ternary(parser)
}