nifty_interp/machine/
walk.rs1use std::rc::Rc;
4
5use nifty_check::hir::{Iterable, Loop};
6use nifty_syntax::Span;
7
8use super::{Frame, Location, Machine, Result, Slot};
9use crate::value::Value;
10
11pub(crate) enum Walk {
13 Place(Location, Span),
15 Items(Rc<Vec<Value>>),
16 Range {
17 start: i64,
18 end: i64,
19 },
20}
21
22impl Machine {
23 pub(crate) fn walk(&self, iterable: &Iterable, frame: &mut Frame) -> Result<Walk> {
24 Ok(match iterable {
25 Iterable::Place(place) => Walk::Place(self.locate(place, frame)?, place.span),
26 Iterable::Value(list) => match self.eval(list, frame)? {
27 Value::List(items) => Walk::Items(items),
28 other => panic!("the checker only allows looping over lists, not {other:?}"),
29 },
30 Iterable::Range { start, end } => Walk::Range {
31 start: self.eval(start, frame)?.as_int(),
32 end: self.eval(end, frame)?.as_int(),
33 },
34 })
35 }
36
37 pub(crate) fn enter_round(
40 &self,
41 head: &Loop,
42 walk: &Walk,
43 (position, index): (usize, i64),
44 frame: &mut Frame,
45 ) -> Result<bool> {
46 let item = match walk {
47 Walk::Place(location, span) => {
48 if position >= list_len(&self.read(location, frame, *span)?) {
49 return Ok(false);
50 }
51 Slot::Alias(location.item(position))
52 }
53 Walk::Items(items) => match items.get(position) {
54 Some(item) => Slot::Value(item.clone()),
55 None => return Ok(false),
56 },
57 Walk::Range { start, end } => match start.checked_add(index) {
58 Some(count) if count < *end => Slot::Value(Value::Int(count)),
59 _ => return Ok(false),
60 },
61 };
62 frame[head.item.0] = item;
63 if let Some(local) = head.index {
64 frame[local.0] = Slot::Value(Value::Int(index));
65 }
66 Ok(true)
67 }
68}
69
70pub(crate) fn rounds() -> impl Iterator<Item = (usize, i64)> {
72 (0..).zip(0..)
73}
74
75fn list_len(list: &Value) -> usize {
76 match list {
77 Value::List(items) => items.len(),
78 other => panic!("the checker only allows looping over lists, not {other:?}"),
79 }
80}