1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
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) },
Operator::Length => { pop!(a); push!(width(a) as isize) },
}
return Ok(());
}
}
/// Find the number of bits required to hold an integer.
pub fn width(value: isize) -> u32 {
match value.cmp(&0) {
std::cmp::Ordering::Less => (-value).ilog2() + 2,
std::cmp::Ordering::Equal => 0,
std::cmp::Ordering::Greater => value.ilog2() + 1,
}
}
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);
}
|