summaryrefslogtreecommitdiff
path: root/src/types
diff options
context:
space:
mode:
authorBen Bridle <ben@derelict.engineering>2025-10-14 20:40:39 +1300
committerBen Bridle <ben@derelict.engineering>2025-10-14 21:05:05 +1300
commit981bb70e5077bd30ef85a0092117a875dcc614fc (patch)
tree45e614de74d17071ca1e68098df4d32266df85a3 /src/types
parentace5677f87c2bc042d8d5e807ccea9ddcd828c9e (diff)
downloadtorque-asm-981bb70e5077bd30ef85a0092117a875dcc614fc.zip
Implement new intermediate stage
Massive improvement. Label references can be used anywhere in the program, with the program being assembled repeatedly until all labels have stabilised. The bytecode stage will just be a tiny stage tacked onto the end, rather than the old bytecode stage that would resolve labels and expressions.
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.