use std::sync::Arc;
use nom::{IResult, Parser, branch::alt, bytes::complete::tag, character::complete::{char, space0}, combinator::map, multi::{many0, many0_count}, sequence::{pair, preceded}};
use crate::{parser::{doc::StofParseError, expr::{async_expr, await_expr, block_expr, fmt_str::formatted_string_expr, graph::graph_expr, list_expr, literal::literal_expr, map_expr, set_expr, switch_expr, tup_expr, typename_expr, typeof_expr, wrapped_expr}, whitespace::whitespace}, runtime::{instruction::Instruction, instructions::{block::Block, ops::{Op, OpIns}, Base, NOOP, NOT_TRUTHY, TRUTHY}, Num, Val}};
pub fn math_expr(input: &str) -> IResult<&str, Arc<dyn Instruction>, StofParseError> {
let (input, _) = whitespace(input)?;
logical(input)
}
pub(self) fn logical(input: &str) -> IResult<&str, Arc<dyn Instruction>, StofParseError> {
let (input, mut lhs) = compare(input)?;
let (input, ops) = many0(
alt((
map(preceded(pair(tag("&&"), whitespace), compare), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::And, rhs: ins }
}),
map(preceded(pair(tag("||"), whitespace), compare), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::Or, rhs: ins }
})
))
).parse(input)?;
for mut op in ops {
op.lhs = lhs;
lhs = Arc::new(op) as Arc<dyn Instruction>;
}
Ok((input, lhs))
}
pub(self) fn compare(input: &str) -> IResult<&str, Arc<dyn Instruction>, StofParseError> {
let (input, mut lhs) = add_sub(input)?;
let (input, ops) = many0(
alt((
map(preceded(pair(tag("=="), whitespace), add_sub), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::Eq, rhs: ins }
}),
map(preceded(pair(tag("!="), whitespace), add_sub), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::Neq, rhs: ins }
}),
map(preceded(pair(tag(">="), whitespace), add_sub), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::GreaterOrEq, rhs: ins }
}),
map(preceded(pair(tag("<="), whitespace), add_sub), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::LessOrEq, rhs: ins }
}),
map(preceded(pair(char('>'), whitespace), add_sub), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::Greater, rhs: ins }
}),
map(preceded(pair(char('<'), whitespace), add_sub), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::Less, rhs: ins }
})
))
).parse(input)?;
for mut op in ops {
op.lhs = lhs;
lhs = Arc::new(op) as Arc<dyn Instruction>;
}
Ok((input, lhs))
}
pub(self) fn add_sub(input: &str) -> IResult<&str, Arc<dyn Instruction>, StofParseError> {
let (input, mut lhs) = mul_div(input)?;
let (input, ops) = many0(
alt((
map(preceded(pair(char('-'), whitespace), mul_div), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::Sub, rhs: ins }
}),
map(preceded(pair(char('+'), whitespace), mul_div), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::Add, rhs: ins }
})
))
).parse(input)?;
for mut op in ops {
op.lhs = lhs;
lhs = Arc::new(op) as Arc<dyn Instruction>;
}
Ok((input, lhs))
}
pub(self) fn mul_div(input: &str) -> IResult<&str, Arc<dyn Instruction>, StofParseError> {
let (input, mut lhs) = bitwise(input)?;
let (input, ops) = many0(
alt((
map(preceded(pair(char('*'), whitespace), bitwise), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::Mul, rhs: ins }
}),
map(preceded(pair(char('/'), whitespace), bitwise), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::Div, rhs: ins }
}),
map(preceded(pair(char('%'), whitespace), bitwise), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::Mod, rhs: ins }
})
))
).parse(input)?;
for mut op in ops {
op.lhs = lhs;
lhs = Arc::new(op) as Arc<dyn Instruction>;
}
Ok((input, lhs))
}
pub(self) fn bitwise(input: &str) -> IResult<&str, Arc<dyn Instruction>, StofParseError> {
let (input, mut lhs) = primary(input)?;
let (input, ops) = many0(
alt((
map(preceded(pair(char('&'), whitespace), primary), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::BAND, rhs: ins }
}),
map(preceded(pair(char('|'), whitespace), primary), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::BOR, rhs: ins }
}),
map(preceded(pair(char('^'), whitespace), primary), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::BXOR, rhs: ins }
}),
map(preceded(pair(tag("<<"), whitespace), primary), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::BSHL, rhs: ins }
}),
map(preceded(pair(tag(">>"), whitespace), primary), |ins| {
OpIns { lhs: NOOP.clone(), op: Op::BSHR, rhs: ins }
})
))
).parse(input)?;
for mut op in ops {
op.lhs = lhs;
lhs = Arc::new(op) as Arc<dyn Instruction>;
}
Ok((input, lhs))
}
fn primary(input: &str) -> IResult<&str, Arc<dyn Instruction>, StofParseError> {
let (input, _) = space0(input)?;
let (input, not_count) = many0_count(char('!')).parse(input)?;
if not_count > 0 {
let (input, ins) = atom.parse(input)?;
let mut block = Block::default();
block.ins.push_back(ins);
if not_count % 2 == 0 {
block.ins.push_back(TRUTHY.clone());
} else {
block.ins.push_back(NOT_TRUTHY.clone());
}
let (input, _) = space0(input)?;
return Ok((input, Arc::new(block)));
}
let (input, ins) = alt((
atom,
map(preceded(char('-'), atom), |ins| {
Arc::new(OpIns { lhs: Arc::new(Base::Literal(Val::Num(Num::Int(-1)))), op: Op::Mul, rhs: ins }) as Arc<dyn Instruction>
})
)).parse(input)?;
let (input, _) = space0(input)?;
Ok((input, ins))
}
fn atom(input: &str) -> IResult<&str, Arc<dyn Instruction>, StofParseError> {
alt([
await_expr,
async_expr,
typename_expr,
typeof_expr,
tup_expr,
list_expr,
set_expr,
map_expr,
block_expr,
switch_expr,
literal_expr,
formatted_string_expr,
graph_expr,
wrapped_expr,
]).parse(input)
}
#[cfg(test)]
mod tests {
use crate::{model::Graph, parser::expr::math::math_expr, runtime::Runtime};
#[test]
fn add() {
let (_input, res) = math_expr("6 + 3").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 9.into());
}
#[test]
fn sub() {
let (_input, res) = math_expr("6 - 3").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 3.into());
}
#[test]
fn mul() {
let (_input, res) = math_expr("6 * 3").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 18.into());
}
#[test]
fn div() {
let (_input, res) = math_expr("6 / 3").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 2.into());
}
#[test]
fn rem() {
let (_input, res) = math_expr("6 % 3").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 0.into());
}
#[test]
fn wrapped() {
let (_input, res) = math_expr("6 + (3 - ( 4g ))").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 5.into());
}
#[test]
fn mul_before_add() {
let (_input, res) = math_expr("6 + 2 * 2").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 10.into());
}
#[test]
fn div_before_sub() {
let (_input, res) = math_expr("35 - 10 / 2").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 30.into());
}
#[test]
fn order() {
let (_input, res) = math_expr("4 + 2 * 3 / 6 - 5").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 0.into());
}
#[test]
fn together() {
let (_input, res) = math_expr("4 + 2 * -(3 / 6) - -5 * (5 % 3)").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, (4 + 2 * -(3 / 6) - -5 * (5 % 3)).into());
}
#[test]
fn less() {
let (_input, res) = math_expr("78 < 100").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, true.into());
}
#[test]
fn greater() {
let (_input, res) = math_expr("78 > 100").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, false.into());
}
#[test]
fn less_or_eq() {
let (_input, res) = math_expr("100 <= 100").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, true.into());
}
#[test]
fn greater_or_eq() {
let (_input, res) = math_expr("101 >= 100").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, true.into());
}
#[test]
fn equal() {
let (_input, res) = math_expr("100 == 100").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, true.into());
}
#[test]
fn not_equal() {
let (_input, res) = math_expr("70 + 30 != 100").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, false.into());
}
#[test]
fn bit_and() {
let (_input, res) = math_expr("0b1010 & 0b0110").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 0b0010.into());
}
#[test]
fn bit_or() {
let (_input, res) = math_expr("0b1010 | 0b0110").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 0b1110.into());
}
#[test]
fn bit_xor() {
let (_input, res) = math_expr("0b1010 ^ 0b0110").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 0b1100.into());
}
#[test]
fn bit_shl() {
let (_input, res) = math_expr("0b0011 << 2").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 0b1100.into());
}
#[test]
fn bit_shr() {
let (_input, res) = math_expr("0b1100 >> 3").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, 0b0001.into());
}
#[test]
fn logical_and() {
let (_input, res) = math_expr("5 && !false").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, true.into());
}
#[test]
fn logical_or() {
let (_input, res) = math_expr("5 || !!(false)").unwrap();
let mut graph = Graph::default();
let val = Runtime::eval(&mut graph, res).unwrap();
assert_eq!(val, true.into());
}
}