wire4/
vm.rs

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}