1use std::rc::{Rc, Weak};
5use std::sync::Arc;
6
7use nifty_check::hir::{Binding, Block, Dynamic, Expr, Loop, StateSet, ViewId};
8use nifty_runtime::{Backend, Dialogs, Engine, Logic, Shown, Templates, Ui, Waker, WindowRequest};
9
10use crate::machine::{
11 Answer, Frame, Machine, Result, RuntimeError, Slot, Targets, new_frame, rounds,
12};
13use crate::value::Value;
14
15pub(crate) struct Interpreter {
16 machine: Machine,
17 downloads: nifty_download::Downloads<Targets>,
18 dialogs: Dialogs<Answer>,
19 views: Vec<ViewTemplate>,
21}
22
23#[derive(Debug)]
25pub(crate) struct ViewTemplate {
26 pub body: Templates<Interpreter>,
27 pub locals: usize,
28}
29
30#[derive(Debug)]
31pub(crate) enum Region {
32 If {
34 branches: Vec<(Rc<Expr>, Templates<Interpreter>)>,
35 otherwise: Templates<Interpreter>,
36 },
37 For {
39 head: Rc<Loop>,
40 body: Templates<Interpreter>,
41 },
42 View { view: ViewId, args: Rc<[Expr]> },
44}
45
46impl Interpreter {
47 pub(crate) fn new<B: Backend>(
50 machine: Machine,
51 ui: &Ui<B>,
52 engine: Weak<Engine<Self, B>>,
53 ) -> Self {
54 let waker: Arc<dyn Waker> = Arc::new(ui.waker(Box::new(move || {
55 if let Some(engine) = engine.upgrade() {
56 engine.logic().dialogs.show_asked();
57 engine.handle_event(Self::receive);
58 }
59 })));
60 Self {
61 views: crate::lower::views(machine.program()),
62 machine,
63 downloads: nifty_download::Downloads::new(Arc::clone(&waker)),
64 dialogs: Dialogs::new(ui.dialogs(), waker),
65 }
66 }
67
68 pub(crate) fn machine(&self) -> &Machine {
69 &self.machine
70 }
71
72 #[cfg(test)]
74 pub(crate) fn wait_for_downloads(&self) {
75 self.downloads.wait();
76 }
77
78 #[cfg(test)]
80 pub(crate) fn wait_for_download_report(&self) {
81 self.downloads.wait_for_report();
82 }
83
84 fn event(&self, run: impl FnOnce(&Machine) -> Result<()>) -> Result<()> {
87 let result = run(&self.machine);
88 for request in self.machine.take_downloads() {
89 self.downloads.start(request);
90 }
91 for (command, id) in self.machine.take_download_commands() {
92 self.downloads.command(&id, command);
93 }
94 self.downloads
95 .cancel_unheld(|targets| self.machine.follow_download(targets));
96 for (dialog, answer) in self.machine.take_dialogs() {
97 self.dialogs.ask(dialog, answer);
98 }
99 result
100 }
101
102 fn receive(&self) -> Result<()> {
103 self.downloads.receive(
104 |targets| self.machine.follow_download(targets),
105 |targets, report| self.machine.report_download(targets, report),
106 )?;
107 self.dialogs
108 .receive(|answer, picked| self.machine.answer_dialog(answer, picked))
109 }
110
111 fn read(&self, binding: &Binding, frame: &Frame) -> Result<Value> {
112 let mut scratch = frame.clone();
113 let location = self.machine.locate(&binding.place, &mut scratch)?;
114 self.machine.read(&location, &scratch, binding.place.span)
115 }
116
117 fn write(&self, binding: &Binding, frame: &Frame, value: Value) -> Result<()> {
118 self.event(|machine| {
119 let mut scratch = frame.clone();
120 let location = machine.locate(&binding.place, &mut scratch)?;
121 machine.write(&location, &mut scratch, value, binding.place.span)
122 })
123 }
124
125 fn round_frames(&self, head: &Loop, frame: &Frame) -> Result<Vec<Rc<Frame>>> {
127 let mut scratch = frame.clone();
128 let walk = self.machine.walk(&head.iterable, &mut scratch)?;
129 let mut frames = Vec::new();
130 for round in rounds() {
131 let mut round_frame = frame.clone();
132 if !self
133 .machine
134 .enter_round(head, &walk, round, &mut round_frame)?
135 {
136 break;
137 }
138 frames.push(Rc::new(round_frame));
139 }
140 Ok(frames)
141 }
142}
143
144impl Logic for Interpreter {
145 type Frame = Frame;
146 type Value = Rc<Dynamic>;
147 type Binding = Rc<Binding>;
148 type Action = Block;
149 type Region = Region;
150 type Error = RuntimeError;
151
152 fn text(&self, text: &Rc<Dynamic>, frame: &Frame) -> Result<String> {
153 let value = self.machine.eval(&text.expr, &mut frame.clone())?;
154 Ok(value.as_str().to_owned())
155 }
156
157 fn number(&self, number: &Rc<Dynamic>, frame: &Frame) -> Result<i64> {
158 Ok(self
159 .machine
160 .eval(&number.expr, &mut frame.clone())?
161 .as_int())
162 }
163
164 fn flag(&self, flag: &Rc<Dynamic>, frame: &Frame) -> Result<bool> {
165 Ok(self.machine.eval(&flag.expr, &mut frame.clone())?.as_bool())
166 }
167
168 fn texts(&self, texts: &Rc<Dynamic>, frame: &Frame) -> Result<Vec<String>> {
169 Ok(match self.machine.eval(&texts.expr, &mut frame.clone())? {
170 Value::List(items) => items.iter().map(|item| item.as_str().to_owned()).collect(),
171 other => panic!("the checker only shows lists of text here, not {other:?}"),
172 })
173 }
174
175 fn read_number(&self, binding: &Rc<Binding>, frame: &Frame) -> Result<i64> {
176 Ok(self.read(binding, frame)?.as_int())
177 }
178
179 fn read_text(&self, binding: &Rc<Binding>, frame: &Frame) -> Result<String> {
180 Ok(self.read(binding, frame)?.as_str().to_owned())
181 }
182
183 fn read_checked(&self, binding: &Rc<Binding>, frame: &Frame) -> Result<bool> {
184 Ok(self.read(binding, frame)?.as_bool())
185 }
186
187 fn write_text(&self, binding: &Rc<Binding>, frame: &Frame, text: &str) -> Result<()> {
188 self.write(binding, frame, Value::String(Rc::from(text)))
189 }
190
191 fn write_checked(&self, binding: &Rc<Binding>, frame: &Frame, checked: bool) -> Result<()> {
192 self.write(binding, frame, Value::Bool(checked))
193 }
194
195 fn write_number(&self, binding: &Rc<Binding>, frame: &Frame, number: i64) -> Result<()> {
196 self.write(binding, frame, Value::Int(number))
197 }
198
199 fn write_texts(&self, binding: &Rc<Binding>, frame: &Frame, texts: Vec<String>) -> Result<()> {
200 self.write(binding, frame, Value::strings(texts))
201 }
202
203 fn run(&self, action: &Block, frame: &Frame) -> Result<()> {
204 self.event(|machine| {
205 machine.exec_block(action, &mut frame.clone())?;
206 Ok(())
207 })
208 }
209
210 fn expand(&self, region: &Region, frame: &Rc<Frame>) -> Result<Vec<Shown<Self>>> {
211 match region {
212 Region::If {
213 branches,
214 otherwise,
215 } => {
216 let mut scratch = Frame::clone(frame);
217 let mut shown = otherwise;
218 for (condition, body) in branches {
219 if self.machine.eval(condition, &mut scratch)?.as_bool() {
220 shown = body;
221 break;
222 }
223 }
224 Ok(vec![Shown {
225 templates: Rc::clone(shown),
226 frame: Rc::clone(frame),
227 }])
228 }
229 Region::For { head, body } => Ok(self
230 .round_frames(head, frame)?
231 .into_iter()
232 .map(|frame| Shown {
233 templates: Rc::clone(body),
234 frame,
235 })
236 .collect()),
237 Region::View { view, args } => {
238 let view = &self.views[view.0];
239 let mut scratch = Frame::clone(frame);
240 let mut view_frame = new_frame(view.locals);
241 for (slot, arg) in view_frame.iter_mut().zip(args.iter()) {
242 *slot = Slot::Value(self.machine.eval(arg, &mut scratch)?);
243 }
244 Ok(vec![Shown {
245 templates: Rc::clone(&view.body),
246 frame: Rc::new(view_frame),
247 }])
248 }
249 }
250 }
251
252 fn take_changed(&self) -> StateSet {
253 self.machine.take_changed()
254 }
255
256 fn take_window_requests(&self) -> Vec<WindowRequest> {
257 self.machine.take_window_requests()
258 }
259}