summaryrefslogtreecommitdiff
path: root/src/types
diff options
context:
space:
mode:
Diffstat (limited to 'src/types')
-rw-r--r--src/types/expression_stack.rs196
-rw-r--r--src/types/word_template.rs2
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.