use super::ast::ArithExpr;
use super::parser::{BashParser, ParseError, ParseResult};
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum ArithToken {
Number(i64),
Variable(String),
Plus,
Minus,
Multiply,
Divide,
Modulo,
LeftParen,
RightParen,
Lt, Le, Gt, Ge, Eq, Ne, Question, Colon, BitAnd, BitOr, BitXor, BitNot, ShiftLeft, ShiftRight, Power, Assign, Comma, LogicalAnd, LogicalOr, LogicalNot, }
mod arith_prec {
use super::{ArithExpr, ArithToken, ParseError, ParseResult};
pub(super) fn parse_comma(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_assign(tokens, pos)?;
while *pos < tokens.len() && matches!(tokens[*pos], ArithToken::Comma) {
*pos += 1;
let right = parse_assign(tokens, pos)?;
left = right;
}
Ok(left)
}
fn parse_assign(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
parse_ternary(tokens, pos)
}
fn parse_ternary(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let cond = parse_logical_or(tokens, pos)?;
if *pos < tokens.len() && matches!(tokens[*pos], ArithToken::Question) {
*pos += 1;
let then_expr = parse_ternary(tokens, pos)?;
if *pos >= tokens.len() || !matches!(tokens[*pos], ArithToken::Colon) {
return Err(ParseError::InvalidSyntax(
"Expected ':' in ternary expression".to_string(),
));
}
*pos += 1;
let else_expr = parse_ternary(tokens, pos)?;
return Ok(ArithExpr::Add(
Box::new(ArithExpr::Mul(Box::new(cond.clone()), Box::new(then_expr))),
Box::new(ArithExpr::Mul(
Box::new(ArithExpr::Sub(
Box::new(ArithExpr::Number(1)),
Box::new(cond),
)),
Box::new(else_expr),
)),
));
}
Ok(cond)
}
fn parse_logical_or(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_logical_and(tokens, pos)?;
while *pos < tokens.len() && matches!(tokens[*pos], ArithToken::LogicalOr) {
*pos += 1;
let right = parse_logical_and(tokens, pos)?;
left = ArithExpr::Add(Box::new(left), Box::new(right)); }
Ok(left)
}
fn parse_logical_and(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_bitwise_or(tokens, pos)?;
while *pos < tokens.len() && matches!(tokens[*pos], ArithToken::LogicalAnd) {
*pos += 1;
let right = parse_bitwise_or(tokens, pos)?;
left = ArithExpr::Mul(Box::new(left), Box::new(right)); }
Ok(left)
}
fn parse_bitwise_or(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_bitwise_xor(tokens, pos)?;
while *pos < tokens.len() && matches!(tokens[*pos], ArithToken::BitOr) {
*pos += 1;
let right = parse_bitwise_xor(tokens, pos)?;
left = ArithExpr::Add(Box::new(left), Box::new(right));
}
Ok(left)
}
fn parse_bitwise_xor(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_bitwise_and(tokens, pos)?;
while *pos < tokens.len() && matches!(tokens[*pos], ArithToken::BitXor) {
*pos += 1;
let right = parse_bitwise_and(tokens, pos)?;
left = ArithExpr::Sub(Box::new(left), Box::new(right)); }
Ok(left)
}
fn parse_bitwise_and(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_equality(tokens, pos)?;
while *pos < tokens.len() && matches!(tokens[*pos], ArithToken::BitAnd) {
*pos += 1;
let right = parse_equality(tokens, pos)?;
left = ArithExpr::Mul(Box::new(left), Box::new(right)); }
Ok(left)
}
fn parse_equality(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_comparison(tokens, pos)?;
while *pos < tokens.len() {
match &tokens[*pos] {
ArithToken::Eq | ArithToken::Ne => {
*pos += 1;
let right = parse_comparison(tokens, pos)?;
left = ArithExpr::Sub(Box::new(left), Box::new(right));
}
_ => break,
}
}
Ok(left)
}
fn parse_comparison(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_shift(tokens, pos)?;
while *pos < tokens.len() {
match &tokens[*pos] {
ArithToken::Lt | ArithToken::Le | ArithToken::Gt | ArithToken::Ge => {
*pos += 1;
let right = parse_shift(tokens, pos)?;
left = ArithExpr::Sub(Box::new(left), Box::new(right));
}
_ => break,
}
}
Ok(left)
}
fn parse_shift(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_additive(tokens, pos)?;
while *pos < tokens.len() {
match &tokens[*pos] {
ArithToken::ShiftLeft => {
*pos += 1;
let right = parse_additive(tokens, pos)?;
left = ArithExpr::Mul(Box::new(left), Box::new(right));
}
ArithToken::ShiftRight => {
*pos += 1;
let right = parse_additive(tokens, pos)?;
left = ArithExpr::Div(Box::new(left), Box::new(right));
}
_ => break,
}
}
Ok(left)
}
fn parse_additive(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_multiplicative(tokens, pos)?;
while *pos < tokens.len() {
match &tokens[*pos] {
ArithToken::Plus => {
*pos += 1;
let right = parse_multiplicative(tokens, pos)?;
left = ArithExpr::Add(Box::new(left), Box::new(right));
}
ArithToken::Minus => {
*pos += 1;
let right = parse_multiplicative(tokens, pos)?;
left = ArithExpr::Sub(Box::new(left), Box::new(right));
}
_ => break,
}
}
Ok(left)
}
fn parse_multiplicative(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let mut left = parse_power(tokens, pos)?;
while *pos < tokens.len() {
match &tokens[*pos] {
ArithToken::Multiply => {
*pos += 1;
let right = parse_power(tokens, pos)?;
left = ArithExpr::Mul(Box::new(left), Box::new(right));
}
ArithToken::Divide => {
*pos += 1;
let right = parse_power(tokens, pos)?;
left = ArithExpr::Div(Box::new(left), Box::new(right));
}
ArithToken::Modulo => {
*pos += 1;
let right = parse_power(tokens, pos)?;
left = ArithExpr::Mod(Box::new(left), Box::new(right));
}
_ => break,
}
}
Ok(left)
}
fn parse_power(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
let base = parse_unary(tokens, pos)?;
if *pos < tokens.len() && matches!(&tokens[*pos], ArithToken::Power) {
*pos += 1;
let exponent = parse_power(tokens, pos)?;
Ok(ArithExpr::Mul(Box::new(base), Box::new(exponent)))
} else {
Ok(base)
}
}
fn parse_unary(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
if *pos >= tokens.len() {
return Err(ParseError::InvalidSyntax(
"Unexpected end of arithmetic expression".to_string(),
));
}
match &tokens[*pos] {
ArithToken::Minus => {
*pos += 1;
let operand = parse_unary(tokens, pos)?;
Ok(ArithExpr::Sub(
Box::new(ArithExpr::Number(0)),
Box::new(operand),
))
}
ArithToken::BitNot | ArithToken::LogicalNot => {
*pos += 1;
let operand = parse_unary(tokens, pos)?;
Ok(ArithExpr::Sub(
Box::new(ArithExpr::Number(-1)),
Box::new(operand),
))
}
ArithToken::Plus => {
*pos += 1;
parse_unary(tokens, pos)
}
_ => parse_primary(tokens, pos),
}
}
fn parse_primary(tokens: &[ArithToken], pos: &mut usize) -> ParseResult<ArithExpr> {
if *pos >= tokens.len() {
return Err(ParseError::InvalidSyntax(
"Unexpected end of arithmetic expression".to_string(),
));
}
match &tokens[*pos] {
ArithToken::Number(n) => {
let num = *n;
*pos += 1;
Ok(ArithExpr::Number(num))
}
ArithToken::Variable(v) => {
let var = v.clone();
*pos += 1;
Ok(ArithExpr::Variable(var))
}
ArithToken::LeftParen => {
*pos += 1;
let expr = parse_comma(tokens, pos)?;
if *pos >= tokens.len() || !matches!(tokens[*pos], ArithToken::RightParen) {
return Err(ParseError::InvalidSyntax(
"Expected closing parenthesis".to_string(),
));
}
*pos += 1;
Ok(expr)
}
_ => Err(ParseError::InvalidSyntax(format!(
"Unexpected token in arithmetic: {:?}",
tokens[*pos]
))),
}
}
}
include!("parser_arith_bashparser.rs");