summaryrefslogtreecommitdiff
path: root/src/types/expression_stack.rs
diff options
context:
space:
mode:
authorBen Bridle <ben@derelict.engineering>2025-03-06 20:33:27 +1300
committerBen Bridle <ben@derelict.engineering>2025-03-11 16:59:26 +1300
commit1ecee352f5844b0809d7ae66df52e34f42b44c8e (patch)
tree472b6fd57ff7f64ac3f8cd676cbe7a113ba01f05 /src/types/expression_stack.rs
parentf2ed89083f5326a7a6f0a1720033d3388aa431fb (diff)
downloadtorque-asm-1ecee352f5844b0809d7ae66df52e34f42b44c8e.zip
Rewrite entire assembler
The language is now more general, the code is better structured, error reporting is more detailed, and many new language features have been implemented: - conditional blocks - first-class strings - more expression operators - binary literals - negative values - invocations in constant expressions
Diffstat (limited to 'src/types/expression_stack.rs')
-rw-r--r--src/types/expression_stack.rs89
1 files changed, 89 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);
+}