diff options
| author | Ben Bridle <ben@derelict.engineering> | 2025-03-06 20:33:27 +1300 |
|---|---|---|
| committer | Ben Bridle <ben@derelict.engineering> | 2025-03-11 16:59:26 +1300 |
| commit | 1ecee352f5844b0809d7ae66df52e34f42b44c8e (patch) | |
| tree | 472b6fd57ff7f64ac3f8cd676cbe7a113ba01f05 /src/types/expression_stack.rs | |
| parent | f2ed89083f5326a7a6f0a1720033d3388aa431fb (diff) | |
| download | torque-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.rs | 89 |
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); +} |
