use std::sync::Arc;
use arcstr::ArcStr;
use imbl::Vector;
use nom::{bytes::complete::tag, branch::alt, character::complete::{char, multispace0}, combinator::recognize, multi::separated_list1, sequence::{delimited, terminated}, IResult, Parser};
use crate::{parser::{doc::StofParseError, expr::expr, ident::ident, whitespace::whitespace}, runtime::{instruction::Instruction, instructions::{Base, ADD, BIT_AND, BIT_OR, BIT_SHIFT_LEFT, BIT_SHIFT_RIGHT, BIT_XOR, DIVIDE, MODULUS, MULTIPLY, SUBTRACT}}};
pub fn assign(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, _) = whitespace(input)?;
alt((
assign_variable,
add_assign_variable,
sub_assign_variable,
mul_assign_variable,
div_assign_variable,
mod_assign_variable,
band_assign_variable,
bor_assign_variable,
bxor_assign_variable,
bshl_assign_variable,
bshr_assign_variable
)).parse(input)
}
pub(self) fn assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(char('='), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
block.push_back(expr);
block.push_back(Arc::new(Base::SetVariable(varname.to_string().into())));
Ok((input, block))
}
pub(self) fn add_assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(tag("+="), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
let varname: ArcStr = varname.to_string().into();
block.push_back(expr);
block.push_back(Arc::new(Base::LoadVariable(varname.clone(), false, false)) as Arc<dyn Instruction>);
block.push_back(ADD.clone());
block.push_back(Arc::new(Base::SetVariable(varname)));
Ok((input, block))
}
pub(self) fn sub_assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(tag("-="), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
let varname: ArcStr = varname.to_string().into();
block.push_back(expr);
block.push_back(Arc::new(Base::LoadVariable(varname.clone(), false, false)) as Arc<dyn Instruction>);
block.push_back(SUBTRACT.clone());
block.push_back(Arc::new(Base::SetVariable(varname)));
Ok((input, block))
}
pub(self) fn mul_assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(tag("*="), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
let varname: ArcStr = varname.to_string().into();
block.push_back(expr);
block.push_back(Arc::new(Base::LoadVariable(varname.clone(), false, false)) as Arc<dyn Instruction>);
block.push_back(MULTIPLY.clone());
block.push_back(Arc::new(Base::SetVariable(varname)));
Ok((input, block))
}
pub(self) fn div_assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(tag("/="), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
let varname: ArcStr = varname.to_string().into();
block.push_back(expr);
block.push_back(Arc::new(Base::LoadVariable(varname.clone(), false, false)) as Arc<dyn Instruction>);
block.push_back(DIVIDE.clone());
block.push_back(Arc::new(Base::SetVariable(varname)));
Ok((input, block))
}
pub(self) fn mod_assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(tag("%="), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
let varname: ArcStr = varname.to_string().into();
block.push_back(expr);
block.push_back(Arc::new(Base::LoadVariable(varname.clone(), false, false)) as Arc<dyn Instruction>);
block.push_back(MODULUS.clone());
block.push_back(Arc::new(Base::SetVariable(varname)));
Ok((input, block))
}
pub(self) fn band_assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(tag("&="), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
let varname: ArcStr = varname.to_string().into();
block.push_back(expr);
block.push_back(Arc::new(Base::LoadVariable(varname.clone(), false, false)) as Arc<dyn Instruction>);
block.push_back(BIT_AND.clone());
block.push_back(Arc::new(Base::SetVariable(varname)));
Ok((input, block))
}
pub(self) fn bor_assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(tag("|="), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
let varname: ArcStr = varname.to_string().into();
block.push_back(expr);
block.push_back(Arc::new(Base::LoadVariable(varname.clone(), false, false)) as Arc<dyn Instruction>);
block.push_back(BIT_OR.clone());
block.push_back(Arc::new(Base::SetVariable(varname)));
Ok((input, block))
}
pub(self) fn bxor_assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(tag("^="), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
let varname: ArcStr = varname.to_string().into();
block.push_back(expr);
block.push_back(Arc::new(Base::LoadVariable(varname.clone(), false, false)) as Arc<dyn Instruction>);
block.push_back(BIT_XOR.clone());
block.push_back(Arc::new(Base::SetVariable(varname)));
Ok((input, block))
}
pub(self) fn bshl_assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(tag("<<="), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
let varname: ArcStr = varname.to_string().into();
block.push_back(expr);
block.push_back(Arc::new(Base::LoadVariable(varname.clone(), false, false)) as Arc<dyn Instruction>);
block.push_back(BIT_SHIFT_LEFT.clone());
block.push_back(Arc::new(Base::SetVariable(varname)));
Ok((input, block))
}
pub(self) fn bshr_assign_variable(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(multispace0, recognize(separated_list1(char('.'), ident)), multispace0).parse(input)?;
let (input, _) = terminated(tag(">>="), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
let varname: ArcStr = varname.to_string().into();
block.push_back(expr);
block.push_back(Arc::new(Base::LoadVariable(varname.clone(), false, false)) as Arc<dyn Instruction>);
block.push_back(BIT_SHIFT_RIGHT.clone());
block.push_back(Arc::new(Base::SetVariable(varname)));
Ok((input, block))
}