summaryrefslogtreecommitdiff
path: root/src/types
diff options
context:
space:
mode:
Diffstat (limited to 'src/types')
-rw-r--r--src/types/expression_stack.rs89
-rw-r--r--src/types/mod.rs7
-rw-r--r--src/types/operator.rs87
-rw-r--r--src/types/word_template.rs46
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(());
+ }
+}