diff options
Diffstat (limited to 'src/types')
-rw-r--r-- | src/types/expression_stack.rs | 196 | ||||
-rw-r--r-- | src/types/word_template.rs | 2 |
2 files changed, 157 insertions, 41 deletions
diff --git a/src/types/expression_stack.rs b/src/types/expression_stack.rs index 62a44fb..16ce0a0 100644 --- a/src/types/expression_stack.rs +++ b/src/types/expression_stack.rs @@ -2,7 +2,7 @@ use crate::*; pub struct ExpressionStack { - stack: Vec<isize>, + stack: Vec<IntermediateValue>, } impl ExpressionStack { @@ -12,63 +12,170 @@ impl ExpressionStack { } } - pub fn pull_result(mut self) -> Result<isize, StackError> { + pub fn pull_result(mut self) -> Result<isize, ExpressionError> { match self.stack.len() { - 0 => Err(StackError::NoReturnValue), - 1 => Ok(self.stack.pop().unwrap()), - _ => Err(StackError::MultipleReturnValues), + 0 => Err(ExpressionError::NoReturnValue), + 1 => { + match self.stack.pop().unwrap() { + IntermediateValue::Integer(value) => Ok(*value), + IntermediateValue::List(_) => Err(ExpressionError::InvalidReturnType("a list")), + IntermediateValue::Block(_) => Err(ExpressionError::InvalidReturnType("a block")), + } + } + _ => Err(ExpressionError::MultipleReturnValues), } } - pub fn push(&mut self, value: isize) { + pub fn push(&mut self, value: IntermediateValue) { self.stack.push(value); } - pub fn apply(&mut self, operator: Operator, source: &SourceSpan) -> Result<(), Tracked<StackError>> { + pub fn apply(&mut self, operator: Operator, source: &SourceSpan) -> Result<(), Tracked<ExpressionError>> { macro_rules! push { - ($val:expr) => { self.stack.push($val) } + ($res:expr) => { + match $res { + Ok(value) => self.stack.push(value), + Err(error) => return Err(Tracked::from(error, source.clone())), + } + } } macro_rules! pop { ($name:ident) => { let $name = match self.stack.pop() { Some(value) => value, - None => return Err(Tracked::from(StackError::Underflow, source.clone())), + None => return Err(Tracked::from(ExpressionError::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) }, - Operator::Length => { pop!(a); push!(width(a) as isize) }, - Operator::Sum => { pop!(a); push!(ones(a) as isize) }, - Operator::Absolute => { pop!(a); push!(a.wrapping_abs()) }, + Operator::Equal => { pop!(b); pop!(a); push!(op_equal(a, b)) }, + Operator::NotEqual => { pop!(b); pop!(a); push!(op_not_equal(a, b)) }, + Operator::LessThan => { pop!(b); pop!(a); push!(op_less_than(a, b)) }, + Operator::GreaterThan => { pop!(b); pop!(a); push!(op_greater_than(a, b)) }, + Operator::LessThanEqual => { pop!(b); pop!(a); push!(op_less_than_equal(a, b)) }, + Operator::GreaterThanEqual => { pop!(b); pop!(a); push!(op_greater_than_equal(a, b)) }, + Operator::Add => { pop!(b); pop!(a); push!(op_add(a, b)) }, + Operator::Subtract => { pop!(b); pop!(a); push!(op_subtract(a, b)) }, + Operator::Multiply => { pop!(b); pop!(a); push!(op_multiply(a, b)) }, + Operator::Divide => { pop!(b); pop!(a); push!(op_divide(a, b)) }, + Operator::Modulo => { pop!(b); pop!(a); push!(op_modulo(a, b)) }, + Operator::Exponent => { pop!(b); pop!(a); push!(op_exponent(a, b)) }, + Operator::LeftShift => { pop!(b); pop!(a); push!(op_left_shift(a, b)) }, + Operator::RightShift => { pop!(b); pop!(a); push!(op_right_shift(a, b)) }, + Operator::BitAnd => { pop!(b); pop!(a); push!(op_bit_and(a, b)) }, + Operator::BitOr => { pop!(b); pop!(a); push!(op_bit_or(a, b)) }, + Operator::BitXor => { pop!(b); pop!(a); push!(op_bit_xor(a, b)) }, + Operator::BitNot => { pop!(a); push!(op_bit_not(a)) }, + Operator::Length => { pop!(a); push!(op_length(a)) }, + Operator::Sum => { pop!(a); push!(op_sum(a)) }, + Operator::Absolute => { pop!(a); push!(op_absolute(a)) }, } return Ok(()); } } +// Generate fake tracking information for synthetic values. +fn null_span() -> SourceSpan { + SourceSpan { + string: String::new(), + in_merged: SourceLocation { + path: None, + start: SourcePosition { line: 0, column: 0 }, + end: SourcePosition { line: 0, column: 0 }, + }, + in_source: None, + child: None, + } +} + +fn to_isize(value: IntermediateValue) -> Result<isize, ExpressionError> { + let received = match value { + IntermediateValue::Integer(integer) => return Ok(integer.value), + IntermediateValue::List(_) => "a list", + IntermediateValue::Block(_) => "a block", + }; + Err(ExpressionError::InvalidArgumentType("an integer", received)) +} + +fn from_isize(value: isize) -> IntermediateValue { + IntermediateValue::Integer(Tracked::from(value, null_span())) +} + +fn from_bool(value: bool) -> IntermediateValue { + // Source span isn't used by anything. + match value { + true => IntermediateValue::Integer(Tracked::from(1, null_span())), + false => IntermediateValue::Integer(Tracked::from(0, null_span())), + } +} + +fn op_equal(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_bool(to_isize(l)? == to_isize(r)?)) } +fn op_not_equal(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_bool(to_isize(l)? != to_isize(r)?)) } +fn op_less_than(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_bool(to_isize(l)? < to_isize(r)?)) } +fn op_greater_than(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_bool(to_isize(l)? > to_isize(r)?)) } +fn op_less_than_equal(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_bool(to_isize(l)? <= to_isize(r)?)) } +fn op_greater_than_equal(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_bool(to_isize(l)? >= to_isize(r)?)) } +fn op_add(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_isize(to_isize(l)? + to_isize(r)?)) } +fn op_subtract(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_isize(to_isize(l)? - to_isize(r)?)) } +fn op_multiply(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_isize(to_isize(l)? * to_isize(r)?)) } +fn op_divide(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_isize(to_isize(l)? / to_isize(r)?)) } +fn op_modulo(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_isize(to_isize(l)? % to_isize(r)?)) } +fn op_exponent(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + let l = to_isize(l)?; let r = to_isize(r)?; + if let Ok(r) = u32::try_from(r) { + Ok(from_isize(l.saturating_pow(r))) + } else { + Ok(from_isize(0)) + } +} +fn op_left_shift(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + let l = to_isize(l)?; let r = to_isize(r)?; + Ok(from_isize(if r < 0 { l >> -r } else { l << r })) +} +fn op_right_shift(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + let l = to_isize(l)?; let r = to_isize(r)?; + Ok(from_isize(if r < 0 { l << -r } else { l >> r })) +} +fn op_bit_and(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_isize((to_isize(l)?) & (to_isize(r)?))) } +fn op_bit_or(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_isize((to_isize(l)?) | (to_isize(r)?))) } +fn op_bit_xor(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_isize((to_isize(l)?) ^ (to_isize(r)?))) } +fn op_bit_not(l: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_isize(!to_isize(l)?)) } +fn op_length(l: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + let length = match l { + IntermediateValue::Integer(integer) => width(*integer) as isize, + IntermediateValue::List(list) => list.len() as isize, + IntermediateValue::Block(block) => block.len() as isize, + }; + Ok(from_isize(length)) +} +fn op_sum(l: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + let sum = match l { + IntermediateValue::Integer(integer) => ones(*integer) as isize, + IntermediateValue::List(list) => list.into_iter().map(|t| t.value).sum(), + IntermediateValue::Block(_) => return Err(ExpressionError::InvalidArgumentType("an integer or list", "a block")) + }; + Ok(from_isize(sum)) +} +fn op_absolute(l: IntermediateValue) -> Result<IntermediateValue, ExpressionError> { + Ok(from_isize(to_isize(l)?.wrapping_abs())) } + + /// Find the number of bits required to hold an integer. pub fn width(value: isize) -> u32 { match value.cmp(&0) { @@ -86,22 +193,29 @@ pub fn ones(value: isize) -> u32 { return value.count_ones(); } -pub enum StackError { +pub enum ExpressionError { Underflow, MultipleReturnValues, NoReturnValue, + InvalidReturnType(&'static str), + // (expected, received) + InvalidArgumentType(&'static str, &'static str), } -pub fn report_stack_error(error: &Tracked<StackError>, source_code: &str) { +pub fn report_expression_error(error: &Tracked<ExpressionError>, source_code: &str) { let context = Context { source_code: &source_code, source: &error.source }; let message = match &error.value { - StackError::Underflow => + ExpressionError::Underflow => "A stack underflow occurred while evaluating this operator", - StackError::MultipleReturnValues => + ExpressionError::MultipleReturnValues => "More than one value was left on the stack after this expression was evaluated", - StackError::NoReturnValue => + ExpressionError::NoReturnValue => "No value was left on the stack after this expression was evaluated", + ExpressionError::InvalidReturnType(received) => + &format!("Expression must return an integer value, not {received} value"), + ExpressionError::InvalidArgumentType(expected, received) => + &format!("Operator expected {expected} value, not {received} value"), }; report_source_issue(LogLevel::Error, &context, message); diff --git a/src/types/word_template.rs b/src/types/word_template.rs index 33d5933..634e1d5 100644 --- a/src/types/word_template.rs +++ b/src/types/word_template.rs @@ -1,6 +1,7 @@ use crate::*; +#[derive(Clone)] pub struct WordTemplate { pub value: usize, /// Width of the word in bits. @@ -8,6 +9,7 @@ pub struct WordTemplate { pub fields: Vec<Tracked<BitField>>, } +#[derive(Clone)] pub struct BitField { pub name: char, /// Width of the field in bits. |