nifty_interp/machine/
stmt.rs1use nifty_check::hir::Stmt;
4
5use super::walk::rounds;
6use super::{Frame, Machine, Result, Slot, binary};
7use crate::value::Value;
8
9#[derive(Debug)]
11pub(crate) enum Flow {
12 Normal,
13 Return(Value),
14}
15
16impl Machine {
17 pub(crate) fn exec_block(&self, block: &[Stmt], frame: &mut Frame) -> Result<Flow> {
18 for stmt in block {
19 if let Flow::Return(value) = self.exec(stmt, frame)? {
20 return Ok(Flow::Return(value));
21 }
22 }
23 Ok(Flow::Normal)
24 }
25
26 fn exec(&self, stmt: &Stmt, frame: &mut Frame) -> Result<Flow> {
27 match stmt {
28 Stmt::Let(local, value) => {
29 frame[local.0] = Slot::Value(self.eval(value, frame)?);
30 }
31 Stmt::Assign { place, op, value } => {
32 let mut value = self.eval(value, frame)?;
33 let location = self.locate(place, frame)?;
34 if let Some(op) = op {
35 let current = self.read(&location, frame, place.span)?;
36 value = binary(*op, ¤t, &value, place.span)?;
37 }
38 self.write(&location, frame, value, place.span)?;
39 }
40 Stmt::If {
41 branches,
42 otherwise,
43 } => {
44 for (condition, body) in branches {
45 if self.eval(condition, frame)?.as_bool() {
46 return self.exec_block(body, frame);
47 }
48 }
49 if let Some(otherwise) = otherwise {
50 return self.exec_block(otherwise, frame);
51 }
52 }
53 Stmt::For { head, body } => {
54 let walk = self.walk(&head.iterable, frame)?;
55 for round in rounds() {
56 if !self.enter_round(head, &walk, round, frame)? {
57 break;
58 }
59 if let Flow::Return(value) = self.exec_block(body, frame)? {
60 return Ok(Flow::Return(value));
61 }
62 }
63 }
64 Stmt::Return(value) => {
65 let value = match value {
66 Some(value) => self.eval(value, frame)?,
67 None => Value::Void,
68 };
69 return Ok(Flow::Return(value));
70 }
71 Stmt::Expr(expr) => {
72 self.eval(expr, frame)?;
73 }
74 }
75 Ok(Flow::Normal)
76 }
77}