use std::fmt::{self, Display, Formatter}; use std::ops::Not; use sexp::SourcePosition; use crate::asm::error::CrsnError; /// Condition flag #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum Cond { /// Equality Equal, /// Inequality NotEqual, /// Equal to zero Zero, /// Not equal zero NotZero, /// A < B Lower, /// A <= B LowerOrEqual, /// A > B Greater, /// A >= B GreaterOrEqual, /// A > 0 Positive, /// A <= 0 NonPositive, /// A < 0 Negative, /// A >= 0 NonNegative, /// Arithmetic operation caused an integer operand to overflow Overflow, /// No overflow NotOverflow, /// Arithmetic (or other) operation was invalid. /// Example: division by zero Invalid, /// Operation was valid Valid, /// Arithmetic carry Carry, /// Carry not set NotCarry, // Full Full, /// Not full NotFull, // Empty Empty, /// Not empty NotEmpty, } pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result { Ok(match text.trim_end_matches('?') { "eq" | "=" | "==" => Cond::Equal, "ne" | "<>" | "!=" | "≠" => Cond::NotEqual, "z" | "0" => Cond::Zero, "nz" | "<>0" | "!0" => Cond::NotZero, "lt" | "<" => Cond::Lower, "le" | "<=" | "≤" => Cond::LowerOrEqual, "gt" | ">" => Cond::Greater, "ge" | ">=" | "≥" => Cond::GreaterOrEqual, "pos" | "+" | ">0" => Cond::Positive, "neg" | "-" | "<0" => Cond::Negative, "npos" | "0-" | "<=0" | "≥0" => Cond::NonPositive, "nneg" | "0+" | ">=0" | "≤0" => Cond::NonNegative, "c" => Cond::Carry, "nc" => Cond::NotCarry, "em" => Cond::Empty, "nem" => Cond::NotEmpty, "f" => Cond::Full, "nf" => Cond::NotFull, "valid" => Cond::Valid, "inval" => Cond::Invalid, "ov" => Cond::Overflow, "nov" => Cond::NotOverflow, _ => { return Err(CrsnError::Parse(format!("Unknown cond: {}", text).into(), pos.clone())); } }) } impl Display for Cond { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str(match self { Cond::Equal => "eq", Cond::NotEqual => "ne", Cond::Zero => "z", Cond::NotZero => "nz", Cond::Empty => "emp", Cond::NotEmpty => "nemp", Cond::Full => "full", Cond::NotFull => "nfull", Cond::Lower => "lt", Cond::LowerOrEqual => "le", Cond::Greater => "gt", Cond::GreaterOrEqual => "ge", Cond::Positive => "pos", Cond::Negative => "neg", Cond::NonPositive => "npos", Cond::NonNegative => "nneg", Cond::Overflow => "ov", Cond::NotOverflow => "nov", Cond::Carry => "c", Cond::NotCarry => "nc", Cond::Invalid => "inval", Cond::Valid => "valid", }) } } impl Not for Cond { type Output = Cond; fn not(self) -> Self::Output { match self { Cond::Equal => Cond::NotEqual, Cond::Zero => Cond::NotZero, Cond::Overflow => Cond::NotOverflow, Cond::Carry => Cond::NotCarry, Cond::Empty => Cond::NotEmpty, Cond::NotEmpty => Cond::Empty, Cond::Full => Cond::NotFull, Cond::NotFull => Cond::Full, Cond::Positive => Cond::NonPositive, Cond::Negative => Cond::NonNegative, Cond::NonPositive => Cond::Positive, Cond::NonNegative => Cond::Negative, Cond::NotEqual => Cond::Equal, Cond::NotZero => Cond::Zero, Cond::NotOverflow => Cond::Overflow, Cond::NotCarry => Cond::Carry, Cond::Lower => Cond::GreaterOrEqual, Cond::Greater => Cond::LowerOrEqual, Cond::LowerOrEqual => Cond::Greater, Cond::GreaterOrEqual => Cond::Lower, Cond::Invalid => Cond::Valid, Cond::Valid => Cond::Invalid, } } }