diff options
Diffstat (limited to 'src/types')
-rw-r--r-- | src/types/expression_stack.rs | 89 | ||||
-rw-r--r-- | src/types/mod.rs | 7 | ||||
-rw-r--r-- | src/types/operator.rs | 87 | ||||
-rw-r--r-- | src/types/word_template.rs | 46 |
4 files changed, 229 insertions, 0 deletions
diff --git a/src/types/expression_stack.rs b/src/types/expression_stack.rs new file mode 100644 index 0000000..4d26eb2 --- /dev/null +++ b/src/types/expression_stack.rs @@ -0,0 +1,89 @@ +use crate::*; + + +pub struct ExpressionStack { + stack: Vec<isize>, +} + +impl ExpressionStack { + pub fn new() -> Self { + Self { + stack: Vec::new(), + } + } + + pub fn pull_result(mut self) -> Result<isize, StackError> { + match self.stack.len() { + 0 => Err(StackError::NoReturnValue), + 1 => Ok(self.stack.pop().unwrap()), + _ => Err(StackError::MultipleReturnValues), + } + } + + pub fn push(&mut self, value: isize) { + self.stack.push(value); + } + + pub fn apply(&mut self, operator: Operator, source: &SourceSpan) -> Result<(), Tracked<StackError>> { + macro_rules! push { + ($val:expr) => { self.stack.push($val) } + } + macro_rules! pop { + ($name:ident) => { + let $name = match self.stack.pop() { + Some(value) => value, + None => return Err(Tracked::from(StackError::Underflow, source.clone())), + }; + } + } + macro_rules! truth { + ($bool:expr) => { match $bool { true => 1, false => 0 } }; + } + match operator { + Operator::Equal => { pop!(b); pop!(a); push!(truth!(a==b)) }, + Operator::NotEqual => { pop!(b); pop!(a); push!(truth!(a!=b)) }, + Operator::LessThan => { pop!(b); pop!(a); push!(truth!(a < b)) }, + Operator::GreaterThan => { pop!(b); pop!(a); push!(truth!(a > b)) }, + Operator::LessThanEqual => { pop!(b); pop!(a); push!(truth!(a <= b)) }, + Operator::GreaterThanEqual => { pop!(b); pop!(a); push!(truth!(a >= b)) }, + Operator::Add => { pop!(b); pop!(a); push!(a + b) }, + Operator::Subtract => { pop!(b); pop!(a); push!(a - b) }, + Operator::Multiply => { pop!(b); pop!(a); push!(a * b) }, + Operator::Divide => { pop!(b); pop!(a); push!(a / b) }, + Operator::Modulo => { pop!(b); pop!(a); push!(a % b) }, + Operator::Exponent => { pop!(b); pop!(a); push!( + if let Ok(b) = u32::try_from(b) { a.saturating_pow(b) } else { 0 } ) }, + Operator::LeftShift => { pop!(b); pop!(a); push!( + if b < 0 { a >> -b } else { a << b } ) }, + Operator::RightShift => { pop!(b); pop!(a); push!( + if b < 0 { a << -b } else { a >> b } ) }, + Operator::BitAnd => { pop!(b); pop!(a); push!(a & b) }, + Operator::BitOr => { pop!(b); pop!(a); push!(a | b) }, + Operator::BitXor => { pop!(b); pop!(a); push!(a ^ b) }, + Operator::BitNot => { pop!(a); push!(!a) }, + } + return Ok(()); + } +} + + +pub enum StackError { + Underflow, + MultipleReturnValues, + NoReturnValue, +} + + +pub fn report_stack_error(error: &Tracked<StackError>, source_code: &str) { + let context = Context { source_code: &source_code, source: &error.source }; + let message = match &error.value { + StackError::Underflow => + "A stack underflow occurred while evaluating this operator", + StackError::MultipleReturnValues => + "More than one value was left on the stack after this expression was evaluated", + StackError::NoReturnValue => + "No value was left on the stack after this expression was evaluated", + }; + + report_source_issue(LogLevel::Error, &context, message); +} diff --git a/src/types/mod.rs b/src/types/mod.rs new file mode 100644 index 0000000..623d525 --- /dev/null +++ b/src/types/mod.rs @@ -0,0 +1,7 @@ +mod expression_stack; +mod operator; +mod word_template; + +pub use expression_stack::*; +pub use operator::*; +pub use word_template::*; diff --git a/src/types/operator.rs b/src/types/operator.rs new file mode 100644 index 0000000..a7e7b9b --- /dev/null +++ b/src/types/operator.rs @@ -0,0 +1,87 @@ +#[derive(Clone, Copy)] +pub enum Operator { + Equal, + NotEqual, + LessThan, + GreaterThan, + LessThanEqual, + GreaterThanEqual, + Add, + Subtract, + Multiply, + Divide, + Modulo, + Exponent, + LeftShift, + RightShift, + BitAnd, + BitOr, + BitXor, + BitNot, +} + +impl Operator { + pub fn from_str(string: &str) -> Option<Self> { + match string { + "=" => Some(Operator::Equal), + "==" => Some(Operator::Equal), + "<eq>" => Some(Operator::Equal), + "!=" => Some(Operator::NotEqual), + "<neq>" => Some(Operator::NotEqual), + "<" => Some(Operator::LessThan), + "<lth>" => Some(Operator::LessThan), + ">" => Some(Operator::GreaterThan), + "<gth>" => Some(Operator::GreaterThan), + "<=" => Some(Operator::LessThanEqual), + "<leq>" => Some(Operator::LessThanEqual), + ">=" => Some(Operator::GreaterThanEqual), + "<geq>" => Some(Operator::GreaterThanEqual), + "+" => Some(Operator::Add), + "<add>" => Some(Operator::Add), + "-" => Some(Operator::Subtract), + "<sub>" => Some(Operator::Subtract), + "*" => Some(Operator::Multiply), + "<mul>" => Some(Operator::Multiply), + "/" => Some(Operator::Divide), + "<div>" => Some(Operator::Divide), + "<mod>" => Some(Operator::Modulo), + "**" => Some(Operator::Exponent), + "<exp>" => Some(Operator::Exponent), + "<<" => Some(Operator::LeftShift), + "<shl>" => Some(Operator::LeftShift), + ">>" => Some(Operator::RightShift), + "<shr>" => Some(Operator::RightShift), + "<and>" => Some(Operator::BitAnd), + "<or>" => Some(Operator::BitOr), + "<xor>" => Some(Operator::BitXor), + "<not>" => Some(Operator::BitNot), + _ => None, + } + } +} + +impl std::fmt::Display for Operator { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + let string = match self { + Operator::Equal => "<eq>", + Operator::NotEqual => "<neq>", + Operator::LessThan => "<lth>", + Operator::GreaterThan => "<gth>", + Operator::LessThanEqual => "<leq>", + Operator::GreaterThanEqual => "<geq>", + Operator::Add => "<add>", + Operator::Subtract => "<sub>", + Operator::Multiply => "<mul>", + Operator::Divide => "<div>", + Operator::Modulo => "<mod>", + Operator::Exponent => "<exp>", + Operator::LeftShift => "<shl>", + Operator::RightShift => "<shr>", + Operator::BitAnd => "<and>", + Operator::BitOr => "<or>", + Operator::BitXor => "<xor>", + Operator::BitNot => "<not>", + }; + write!(f, "{string}") + } +} diff --git a/src/types/word_template.rs b/src/types/word_template.rs new file mode 100644 index 0000000..33d5933 --- /dev/null +++ b/src/types/word_template.rs @@ -0,0 +1,46 @@ +use crate::*; + + +pub struct WordTemplate { + pub value: usize, + /// Width of the word in bits. + pub width: u32, + pub fields: Vec<Tracked<BitField>>, +} + +pub struct BitField { + pub name: char, + /// Width of the field in bits. + pub width: u32, + /// Number of bits to the right of the field in the word. + pub shift: u32, +} + + +impl std::fmt::Display for WordTemplate { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + if self.value == 0 { + write!(f, "0")?; + } else { + let bitcount = (self.value.ilog2() + 1) as usize; + 'bit: for i in (0..bitcount).rev() { + let is_first_bit = i+1 == bitcount; + if !is_first_bit && (i+1) % 4 == 0 { + write!(f, "_")?; + } + for field in &self.fields { + let i = i as u32; + if i <= field.width + field.shift - 1 && i >= field.shift { + write!(f, "{}", field.name)?; + continue 'bit; + } + } + match (self.value >> i) & 1 { + 0 => write!(f, "0")?, + _ => write!(f, "1")?, + } + } + } + return Ok(()); + } +} |