1use crate::spool::Spool;
2use crate::*;
3
4#[derive(Debug)]
5pub struct Wire4VM {
6 pc: usize,
7 code: Prog,
8 stack: Stack,
9 scope: ScopeStack,
10 vtable: VTable,
11 vars: Vars,
12 spool: Spool,
13}
14
15#[derive(Debug, PartialEq, Clone)]
16pub enum Cond {
17 Active,
18 Skip,
19 Bypass,
20}
21
22#[derive(Debug, PartialEq, Clone)]
23pub enum Scope {
24 Call(usize),
25 Cond(Cond),
26 Loop(usize),
27 CondLoop(usize, i32, i32),
28}
29
30impl Default for vm::Wire4VM {
31 fn default() -> Self {
32 Self::new()
33 }
34}
35
36impl Wire4VM {
37 pub fn new() -> Wire4VM {
38 Wire4VM {
39 pc: 0,
40 code: Prog::new(),
41 stack: Stack::new(),
42 vtable: VTable::new(),
43 scope: ScopeStack::new(),
44 vars: Vars::new(),
45 spool: Spool::new(),
46 }
47 }
48
49 pub fn reset(&mut self) {
50 self.pc = 0;
51 self.spool.clear();
52 self.vars.clear();
53 self.code.clear();
54 self.stack.clear();
55 self.scope.clear();
56 self.vtable.clear();
57 }
58
59 pub fn load(&mut self, prog: &str) -> Result<(), VMError> {
60 compile(prog, &mut self.code, &mut self.vtable, &mut self.spool)
61 .map_err(VMError::CompileError)?;
62 Ok(())
63 }
64
65 pub fn set_var(&mut self, key: u32, val: Value) -> Result<(), VMError> {
66 self.vars
67 .insert(key, val)
68 .map_err(|_| VMError::TooManyVars)?;
69 Ok(())
70 }
71
72 pub fn get_var(&self, key: u32) -> Option<&Value> {
73 self.vars.get(&key)
74 }
75
76 pub fn get_stack(&self) -> &Stack {
77 &self.stack
78 }
79
80 pub fn get_string(&self, key: u32) -> Option<&String> {
81 self.spool.load(key)
82 }
83
84 pub fn pop(&mut self) -> Result<Value, VMError> {
85 self.stack.pop().ok_or(VMError::StackUnderflow)
86 }
87
88 pub fn push(&mut self, value: Value) -> Result<(), VMError> {
89 self.stack.push(value).map_err(|_| VMError::StackOverflow)
90 }
91
92 pub fn spin(&mut self) -> Result<VMRequest, VMError> {
93 while self.pc < self.code.len() {
94 if let Some(req) = self.tick()? {
95 return Ok(req);
96 }
97 }
98 Ok(VMRequest::Idle)
99 }
100
101 #[allow(clippy::cognitive_complexity)]
102 pub fn tick(&mut self) -> Result<Option<VMRequest>, VMError> {
103 if self.pc >= self.code.len() {
104 return Err(VMError::ProgramHalted);
105 }
106 let op = self.code.get(self.pc).cloned().ok_or(VMError::InvalidPtr)?;
107 let scope = self.scope.get(self.scope.len() - 1).cloned();
108 self.pc = self.pc.saturating_add(1);
109 match (op, scope) {
110 (Word::Proc(proc), _) => {
111 if let Some((_, end)) = self.vtable.get(&proc) {
112 self.pc = *end;
113 return Ok(None);
114 } else {
115 return Err(VMError::InvalidPtr);
116 }
117 }
118 (Word::Call(proc), _) => {
119 if let Some((addr, _)) = self.vtable.get(&proc) {
120 self.scope
121 .push(Scope::Call(self.pc))
122 .map_err(|_| VMError::StackOverflow)?;
123 self.pc = *addr;
124 return Ok(None);
125 } else {
126 return Ok(Some(VMRequest::CallProc(proc)));
127 }
128 }
129 (Word::Ret, _) => match self.scope.pop() {
130 Some(Scope::Call(ra)) => {
131 self.pc = ra;
132 return Ok(None);
133 }
134 _ => return Err(VMError::InvalidScope),
135 },
136 (Word::Else, Some(Scope::Cond(Cond::Bypass))) => {
137 return Ok(None);
138 }
139 (Word::Else, Some(Scope::Cond(Cond::Active))) => {
140 self.patch_scope(Scope::Cond(Cond::Skip))?;
141 return Ok(None);
142 }
143 (Word::Else, Some(Scope::Cond(Cond::Skip))) => {
144 self.patch_scope(Scope::Cond(Cond::Active))?;
145 return Ok(None);
146 }
147 (Word::Else, _) => return Err(VMError::InvalidScope),
148 (Word::Then, Some(Scope::Cond(_))) => {
149 self.scope.pop();
150 return Ok(None);
151 }
152 (Word::Then, _) => {
153 return Err(VMError::InvalidScope);
154 }
155 (Word::If, scope) => {
156 if let Value::Num(flag) = self.pop()? {
157 let cond = match (scope, flag) {
158 (Some(Scope::Cond(Cond::Skip)), _)
159 | (Some(Scope::Cond(Cond::Bypass)), _) => Cond::Bypass,
160 (_, 0) => Cond::Skip,
161 _ => Cond::Active,
162 };
163 self.scope
164 .push(Scope::Cond(cond))
165 .map_err(|_| VMError::StackOverflow)?;
166 return Ok(None);
167 }
168 return Err(VMError::InvalidArguments(Word::If));
169 }
170 (_, Some(Scope::Cond(Cond::Skip))) | (_, Some(Scope::Cond(Cond::Bypass))) => {
171 return Ok(None)
172 }
173 (Word::Do, _) => {
174 let start = self.pop()?;
175 let end = self.pop()?;
176 if let (Value::Num(end), Value::Num(start)) = (end, start) {
177 if start == end {
178 return Err(VMError::InvalidArguments(Word::Do));
179 }
180 self.scope
181 .push(Scope::CondLoop(self.pc, start, end))
182 .map_err(|_| VMError::StackOverflow)?;
183 return Ok(None);
184 } else {
185 return Err(VMError::InvalidArguments(Word::Do));
186 }
187 }
188 (Word::I, scope) => {
189 if let Some(Scope::CondLoop(_, i, _)) = scope {
190 self.push(Value::Num(i))?;
191 return Ok(None);
192 }
193 for scope in self.scope.iter().rev() {
194 match scope {
195 Scope::CondLoop(_, i, _) => {
196 #[allow(mutable_borrow_reservation_conflict)]
197 self.push(Value::Num(*i))?;
198 return Ok(None);
199 }
200 Scope::Call(_) => break,
201 _ => {}
202 }
203 }
204 return Err(VMError::InvalidScope);
205 }
206 (Word::Loop, Some(Scope::CondLoop(ra, val, end))) => {
207 let next = val.saturating_add(1);
208 if next < end {
209 self.patch_scope(Scope::CondLoop(ra, next, end))?;
210 self.pc = ra;
211 } else {
212 self.scope.pop();
213 }
214 return Ok(None);
215 }
216 (Word::Loop, _) => return Err(VMError::InvalidScope),
217 (Word::Begin, _) => {
218 self.scope
219 .push(Scope::Loop(self.pc))
220 .map_err(|_| VMError::StackOverflow)?;
221 return Ok(None);
222 }
223 (Word::Until, Some(Scope::Loop(ra))) => {
224 if let Value::Num(flag) = self.pop()? {
225 if flag != 0 {
226 self.pc = ra;
227 } else {
228 self.scope.pop();
229 }
230 return Ok(None);
231 }
232 return Err(VMError::InvalidArguments(Word::Until));
233 }
234 (Word::Until, _) => return Err(VMError::InvalidScope),
235 (op, _) => match op {
236 Word::Drop => {
237 self.pop()?;
238 }
239 Word::Dup => {
240 let fst = self.pop()?;
241 self.push(fst.clone())?;
242 self.push(fst)?;
243 }
244 Word::Swap => {
245 let fst = self.pop()?;
246 let snd = self.pop()?;
247 self.push(fst)?;
248 self.push(snd)?;
249 }
250 Word::Over => {
251 let fst = self.pop()?;
252 let snd = self.pop()?;
253 self.push(snd.clone())?;
254 self.push(fst)?;
255 self.push(snd)?;
256 }
257 Word::Rot => {
258 let fst = self.pop()?;
259 let snd = self.pop()?;
260 let thr = self.pop()?;
261 self.push(fst)?;
262 self.push(snd)?;
263 self.push(thr)?;
264 }
265 Word::RRot => {
266 let fst = self.pop()?;
267 let snd = self.pop()?;
268 let thr = self.pop()?;
269 self.push(fst)?;
270 self.push(thr)?;
271 self.push(snd)?;
272 }
273 Word::Nip => {
274 let fst = self.pop()?;
275 self.pop()?;
276 self.push(fst)?;
277 }
278 Word::Tuck => {
279 let fst = self.pop()?;
280 let snd = self.pop()?;
281 self.push(fst.clone())?;
282 self.push(snd)?;
283 self.push(fst)?;
284 }
285 Word::Inc
286 | Word::Dec
287 | Word::EqZero
288 | Word::LtZero
289 | Word::GtZero
290 | Word::NotEqZero
291 | Word::Invert => {
292 if let Value::Num(num) = self.pop()? {
293 let num = match op {
294 Word::Inc => num.saturating_add(1),
295 Word::Dec => num.saturating_sub(1),
296 Word::EqZero => bool_enc(num == 0),
297 Word::LtZero => bool_enc(num < 0),
298 Word::GtZero => bool_enc(num > 0),
299 Word::NotEqZero => bool_enc(num != 0),
300 Word::Invert => bool_enc(num == 0),
301 _ => unreachable!(),
302 };
303 self.push(Value::Num(num))?;
304 } else {
305 return Err(VMError::InvalidArguments(op));
306 }
307 }
308 Word::Plus
309 | Word::Minus
310 | Word::Div
311 | Word::Mul
312 | Word::Mod
313 | Word::And
314 | Word::Or
315 | Word::Xor
316 | Word::Lt
317 | Word::Gt
318 | Word::Lte
319 | Word::Gte
320 | Word::Eq
321 | Word::NotEq => {
322 let fst = self.pop()?;
323 let snd = self.pop()?;
324 if let (Value::Num(a), Value::Num(b)) = (snd, fst) {
325 let num = match op {
326 Word::Plus => a + b,
327 Word::Minus => a - b,
328 Word::Div => {
329 if b == 0 {
330 return Err(VMError::DivisionByZero);
331 } else {
332 a / b
333 }
334 }
335 Word::Mul => a * b,
336 Word::And => a & b,
337 Word::Mod => a % b,
338 Word::Or => a | b,
339 Word::Xor => a ^ b,
340 Word::Lt => bool_enc(a < b),
341 Word::Gt => bool_enc(a > b),
342 Word::Lte => bool_enc(a <= b),
343 Word::Gte => bool_enc(a >= b),
344 Word::Eq => bool_enc(a == b),
345 Word::NotEq => bool_enc(a != b),
346 _ => unreachable!(),
347 };
348 self.push(Value::Num(num))?;
349 } else {
350 return Err(VMError::InvalidArguments(op));
351 }
352 }
353 Word::NumImm(num) => self.push(Value::Num(num as i32))?,
354 Word::PortImm(port) => self.push(Value::Port(port))?,
355 Word::NetImm(net) => self.push(Value::Net(net))?,
356 Word::StrImm(key) => self.push(Value::Str(key))?,
357 Word::VarImm(net) => self.push(Value::Var(net))?,
358 Word::SetVar => {
359 if let Value::Var(var) = self.pop()? {
360 let val = self.pop()?;
361 self.set_var(var, val)?;
362 } else {
363 return Err(VMError::InvalidArguments(op));
364 }
365 }
366 Word::GetVar => {
367 if let Value::Var(var) = self.pop()? {
368 #[allow(mutable_borrow_reservation_conflict)]
369 match self.get_var(var) {
370 Some(val) => self.push(val.clone())?,
371 None => return Err(VMError::UnknownVar),
372 }
373 } else {
374 return Err(VMError::InvalidArguments(op));
375 }
376 }
377 Word::IO(io) => return Ok(Some(VMRequest::IO(io))),
378 Word::Call(_)
379 | Word::Proc(_)
380 | Word::Ret
381 | Word::If
382 | Word::Then
383 | Word::Else
384 | Word::Begin
385 | Word::Until
386 | Word::I
387 | Word::Do
388 | Word::Loop => unreachable!(),
389 },
390 }
391 Ok(None)
392 }
393
394 fn patch_scope(&mut self, scope: Scope) -> Result<(), VMError> {
395 if self.scope.pop().is_none() {
396 return Err(VMError::InvalidScope);
397 }
398 self.scope.push(scope).map_err(|_| VMError::StackOverflow)?;
399 Ok(())
400 }
401}