Skip to main content

scratch_test_interpreter/
default_state.rs

1use std::collections::{BTreeSet, HashMap};
2
3use either::Either;
4#[cfg(feature = "rand")]
5use rand::RngExt;
6use smodel::{
7    ProjectDoc,
8    attrs::{List, Variable},
9};
10use svalue::{SList, SNumber, SValue};
11
12use crate::state::{OutputKind, State};
13
14#[derive(Debug, PartialEq, PartialOrd, Clone)]
15pub enum Action {
16    Output {
17        kind: crate::state::OutputKind,
18        message: SValue,
19    },
20    AskQuestion {
21        message: SValue,
22    },
23    RequestRandom {
24        from: SNumber,
25        to: SNumber,
26        received: SNumber,
27    },
28    WaitFor {
29        secs: SNumber,
30    },
31}
32
33#[derive(Debug, Default, PartialEq, derive_getters::Getters)]
34pub struct DefaultState {
35    /// All data (variable/list) identifiers which were
36    /// used before initialized
37    ///
38    /// - variables are initialized by set operation
39    /// - lists are initialized by deleting all elements with clear block
40    uninitialized_usages: BTreeSet<Either<Variable, List>>,
41    /// All data (variable/list) identifiers which were
42    /// used to initialize the corresponding data.
43    ///
44    /// - variables are initialized by set operation
45    /// - lists are initialized by deleting all elements with clear block
46    initialized_data: BTreeSet<Either<Variable, List>>,
47    variables: HashMap<Variable, SValue>,
48    lists: HashMap<List, SList>,
49    actions: Vec<Action>,
50
51    answer_index: Option<usize>,
52    answer_inputs: Vec<svalue::ARc<str>>,
53
54    #[cfg(feature = "rand")]
55    randoms: Option<rand::rngs::StdRng>,
56    predefined_randoms: Option<(svalue::ARc<[svalue::SNumber]>, usize)>,
57}
58
59#[allow(unused)]
60impl DefaultState {
61    pub fn new() -> Self {
62        DefaultState {
63            uninitialized_usages: Default::default(),
64            initialized_data: Default::default(),
65            variables: HashMap::new(),
66            lists: HashMap::new(),
67            actions: vec![],
68            answer_index: None,
69            answer_inputs: vec![],
70            #[cfg(feature = "rand")]
71            randoms: None,
72            predefined_randoms: None,
73        }
74    }
75
76    pub fn from_doc(doc: &ProjectDoc, max_list_length: i64) -> Self {
77        let mut s = Self::new();
78        s.add_data_from_doc(doc, max_list_length);
79        s
80    }
81
82    pub fn add_data_from_doc(&mut self, doc: &ProjectDoc, max_length: i64) -> &mut Self {
83        self.add_variables_from_doc(doc)
84            .add_lists_from_doc(doc, max_length)
85    }
86
87    pub fn add_variables_from_doc(&mut self, doc: &ProjectDoc) -> &mut Self {
88        self.variables.extend(
89            doc.targets()
90                .iter()
91                .flat_map(|t| t.variables().values())
92                .cloned(),
93        );
94        self
95    }
96
97    pub fn add_lists_from_doc(&mut self, doc: &ProjectDoc, max_length: i64) -> &mut Self {
98        self.lists
99            .extend(
100                doc.targets()
101                    .iter()
102                    .flat_map(|t| t.lists().values())
103                    .map(|(dataid, v)| {
104                        let mut list = SList::new(max_length);
105                        for i in v {
106                            // TODO: rethink
107                            list.append_item(i.clone());
108                        }
109                        (dataid.clone(), list)
110                    }),
111            );
112        self
113    }
114
115    fn use_uninitialized_list(&mut self, list_id: &List) -> Result<(), <Self as State>::Error> {
116        let list_id = Either::Right(list_id.clone());
117        if !self.initialized_data.contains(&list_id) {
118            self.uninitialized_usages.insert(list_id);
119        }
120        Ok(())
121    }
122
123    fn use_uninitialized_variable(
124        &mut self,
125        variable_id: &Variable,
126    ) -> Result<(), <Self as State>::Error> {
127        let variable_id = Either::Left(variable_id.clone());
128        if !self.initialized_data.contains(&variable_id) {
129            self.uninitialized_usages.insert(variable_id);
130        }
131        Ok(())
132    }
133
134    pub fn output_lines(&self) -> impl DoubleEndedIterator<Item = (&SValue)> {
135        self.output_actions().map(|(_, text)| text)
136    }
137
138    pub fn output_actions(&self) -> impl DoubleEndedIterator<Item = (&OutputKind, &SValue)> {
139        self.actions().iter().flat_map(|a| {
140            if let Action::Output { kind, message } = a {
141                Some((kind, message))
142            } else {
143                None
144            }
145        })
146    }
147    pub fn used_randoms(&self) -> impl DoubleEndedIterator<Item = &SNumber> {
148        self.actions().iter().flat_map(|a| {
149            if let Action::RequestRandom { received, .. } = a {
150                Some(received)
151            } else {
152                None
153            }
154        })
155    }
156
157    #[cfg(feature = "rand")]
158    pub fn set_randoms(&mut self, rng: Option<rand::rngs::StdRng>) -> &mut Self {
159        self.randoms = rng;
160        self
161    }
162    pub fn set_predefined_randoms(
163        &mut self,
164        predefined: svalue::ARc<[svalue::SNumber]>,
165    ) -> &mut Self {
166        self.predefined_randoms = Some((predefined, 0));
167        self
168    }
169    pub fn set_answers(&mut self, answers: Vec<svalue::ARc<str>>) -> &mut Self {
170        self.answer_inputs = answers;
171        self.answer_index = None;
172        self
173    }
174    pub fn variables_mut(&mut self) -> &mut HashMap<Variable, SValue> {
175        &mut self.variables
176    }
177    pub fn lists_mut(&mut self) -> &mut HashMap<List, SList> {
178        &mut self.lists
179    }
180}
181
182#[derive(Debug, PartialEq, PartialOrd, Clone, thiserror::Error)]
183#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
184#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
185#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
186pub enum DefaultStateError {
187    #[error("variable {0:?} does not exist in state")]
188    VariableNotFound(Variable),
189    #[error("list {0:?} does not exist in state")]
190    ListNotFound(List),
191    #[error("list {id:?} is full, no item can be inserted")]
192    ListFull { id: List },
193    #[error("program is not allowed to request random numbers")]
194    RandomsDisabled,
195    #[error("program requested random number that doesn't match predefined ones")]
196    IncompatibleRandomRequested {
197        predefined: SNumber,
198        #[cfg_attr(feature = "utoipa", schema(value_type = Value))]
199        #[cfg_attr(feature = "schemars", schemars(skip))]
200        range: either::Either<(i64, i64), (f64, f64)>,
201    },
202    #[error("program asked question without a predefined answer remaining")]
203    NoMoreAnswers,
204}
205
206impl State for DefaultState {
207    type Error = DefaultStateError;
208
209    fn ask_question(&mut self, question: SValue) -> Result<(), Self::Error> {
210        self.actions.push(Action::AskQuestion { message: question });
211        self.answer_index = Some(self.answer_index.map(|x| x + 1).unwrap_or(0));
212
213        self.answer_index
214            .and_then(|index| self.answer_inputs.get(index))
215            .ok_or(DefaultStateError::NoMoreAnswers)?;
216        Ok(())
217    }
218    fn last_answer(&mut self) -> Result<&str, Self::Error> {
219        if let Some(index) = self.answer_index {
220            Ok(self
221                .answer_inputs
222                .get(index)
223                .or(self.answer_inputs.last())
224                .map(|s| s.as_ref())
225                .unwrap_or(""))
226        } else {
227            Ok("")
228        }
229    }
230
231    fn request_int_random(
232        &mut self,
233        range: std::ops::RangeInclusive<i64>,
234    ) -> Result<i64, Self::Error> {
235        let received = if let Some((pred, pos)) = self.predefined_randoms.as_mut()
236            && let Some(received) = pred.get(*pos)
237        {
238            match received {
239                SNumber::Float(_) => {
240                    return Err(DefaultStateError::IncompatibleRandomRequested {
241                        predefined: *received,
242                        range: Either::Left(range.into_inner()),
243                    });
244                }
245                SNumber::Int(i) => {
246                    *pos += 1;
247                    *i
248                }
249            }
250        } else {
251            #[cfg(not(feature = "rand"))]
252            return Err(DefaultStateError::RandomsDisabled);
253            #[cfg(feature = "rand")]
254            self.randoms
255                .as_mut()
256                .ok_or(DefaultStateError::RandomsDisabled)?
257                .random_range(range.clone())
258        };
259
260        let (from, to) = range.into_inner();
261        self.actions.push(Action::RequestRandom {
262            from: SNumber::Int(from),
263            to: SNumber::Int(to),
264            received: SNumber::Int(received),
265        });
266        Ok(received)
267    }
268
269    fn request_float_random(
270        &mut self,
271        range: std::ops::RangeInclusive<f64>,
272    ) -> Result<f64, Self::Error> {
273        let received = if let Some((pred, pos)) = self.predefined_randoms.as_mut()
274            && let Some(received) = pred.get(*pos)
275        {
276            match received {
277                SNumber::Int(_) => {
278                    return Err(DefaultStateError::IncompatibleRandomRequested {
279                        predefined: *received,
280                        range: Either::Right(range.into_inner()),
281                    });
282                }
283                SNumber::Float(i) => {
284                    *pos += 1;
285                    *i
286                }
287            }
288        } else {
289            #[cfg(not(feature = "rand"))]
290            return Err(DefaultStateError::RandomsDisabled);
291            #[cfg(feature = "rand")]
292            self.randoms
293                .as_mut()
294                .ok_or(DefaultStateError::RandomsDisabled)?
295                .random_range(range.clone())
296        };
297
298        let (from, to) = range.into_inner();
299        self.actions.push(Action::RequestRandom {
300            from: SNumber::Float(from),
301            to: SNumber::Float(to),
302            received: SNumber::Float(received),
303        });
304        Ok(received)
305    }
306    fn write_output(&mut self, output_kind: crate::state::OutputKind, message: SValue) {
307        self.actions.push(Action::Output {
308            kind: output_kind,
309            message,
310        });
311    }
312
313    fn wait_for_secs(&mut self, secs: SNumber) -> Result<(), Self::Error> {
314        self.actions.push(Action::WaitFor { secs });
315        Ok(())
316    }
317
318    fn data_set_variable(&mut self, var_id: &Variable, value: SValue) -> Result<(), Self::Error> {
319        let store = self
320            .variables
321            .get_mut(var_id)
322            .ok_or_else(|| unknown_var(var_id))?;
323        *store = value;
324        self.initialized_data.insert(Either::Left(var_id.clone()));
325        Ok(())
326    }
327    fn data_read_variable(&mut self, var_id: &Variable) -> Result<&SValue, Self::Error> {
328        self.use_uninitialized_variable(var_id)?;
329        self.variables
330            .get(var_id)
331            .ok_or_else(|| unknown_var(var_id))
332    }
333    fn data_insert_at_list(
334        &mut self,
335        list_id: &List,
336        one_based_index: &SValue,
337        item: SValue,
338    ) -> Result<(), Self::Error> {
339        self.use_uninitialized_list(list_id)?;
340        self.list_mut(list_id)?
341            .insert_item_at(one_based_index, item, &mut ())
342            .map_err(|_err| DefaultStateError::ListFull {
343                id: list_id.clone(),
344            })?;
345        Ok(())
346    }
347    fn data_replace_list_at(
348        &mut self,
349        list_id: &List,
350        one_based_index: &SValue,
351        item: SValue,
352    ) -> Result<(), Self::Error> {
353        self.use_uninitialized_list(list_id)?;
354        self.list_mut(list_id)?
355            .replace_nth_item(one_based_index, item, &mut ());
356        Ok(())
357    }
358    fn data_append_to_list(&mut self, list_id: &List, item: SValue) -> Result<(), Self::Error> {
359        self.use_uninitialized_list(list_id)?;
360        self.list_mut(list_id)?
361            .append_item(item)
362            .map_err(|_err| DefaultStateError::ListFull {
363                id: list_id.clone(),
364            })?;
365        Ok(())
366    }
367    fn data_list_contains_item(
368        &mut self,
369        list_id: &List,
370        item: &SValue,
371    ) -> Result<bool, Self::Error> {
372        self.use_uninitialized_list(list_id)?;
373        Ok(self.list_mut(list_id)?.contains_item(item))
374    }
375    fn data_delete_of_list(
376        &mut self,
377        list_id: &List,
378        one_based_index: &SValue,
379    ) -> Result<(), Self::Error> {
380        self.use_uninitialized_list(list_id)?;
381        self.list_mut(list_id)?.delete_nth(one_based_index, &mut ());
382        Ok(())
383    }
384    fn data_delete_all_of_list(&mut self, list_id: &List) -> Result<(), Self::Error> {
385        self.initialized_data.insert(Either::Right(list_id.clone()));
386        self.list_mut(list_id)?.delete_all();
387        Ok(())
388    }
389    fn data_read_textual_list_repr(&mut self, list_id: &List) -> Result<SValue, Self::Error> {
390        self.use_uninitialized_list(list_id)?;
391        Ok(self.list(list_id)?.textual_representation().into())
392    }
393    fn data_item_num_of_list(&mut self, list_id: &List, item: &SValue) -> Result<i64, Self::Error> {
394        self.use_uninitialized_list(list_id)?;
395        Ok(self.list(list_id)?.first_index_of_item_in_list(item))
396    }
397    fn data_item_of_list(
398        &mut self,
399        list_id: &List,
400        one_based_index: &SValue,
401    ) -> Result<SValue, Self::Error> {
402        self.use_uninitialized_list(list_id)?;
403        Ok(self.list(list_id)?.nth_item(one_based_index, &mut ()))
404    }
405    fn data_length_of_list(&mut self, list_id: &List) -> Result<i64, Self::Error> {
406        self.use_uninitialized_list(list_id)?;
407        Ok(self.list(list_id)?.length())
408    }
409}
410
411fn unknown_var(var_id: &Variable) -> DefaultStateError {
412    DefaultStateError::VariableNotFound(var_id.clone())
413}
414
415fn unknown_list(list_id: &List) -> DefaultStateError {
416    DefaultStateError::ListNotFound(list_id.clone())
417}
418
419impl DefaultState {
420    #[allow(unused)]
421    fn list_mut(&mut self, list_id: &List) -> Result<&mut SList, DefaultStateError> {
422        self.lists
423            .get_mut(list_id)
424            .ok_or_else(|| unknown_list(list_id))
425    }
426    #[allow(unused)]
427    fn list(&mut self, list_id: &List) -> Result<&SList, DefaultStateError> {
428        self.lists.get(list_id).ok_or_else(|| unknown_list(list_id))
429    }
430}