turtle/interpreter/
call_snapshot.rs

1use crate::{exp, Exception, ExceptionValue as EV, Expression, Locker};
2use ansi_term::Color;
3use std::fmt;
4
5#[derive(Debug, Clone)]
6pub struct CallSnapshot {
7    parent: Option<Locker<Self>>,
8    expression: Expression,
9    depth: usize,
10}
11
12impl CallSnapshot {
13    pub fn root(exp: &Expression) -> Locker<Self> {
14        Locker::new(CallSnapshot {
15            parent: None,
16            expression: exp.clone(),
17            depth: 0,
18        })
19    }
20
21    pub fn new(exp: &Expression, parent: &Locker<Self>) -> Result<Locker<Self>, Exception> {
22        // TODO: make read lock check return an exception instead of panicking
23        let depth = parent
24            .read()
25            .expect("could not access call snapshot parent (are threads locked?)")
26            .depth
27            + 1;
28        if depth > 1000 {
29            exp!(
30                EV::StackOverflow,
31                parent,
32                "this can happen when recursion goes too deep; verify there aren't any endless loops, or consider using `while` instead".to_string()
33            )
34        }
35
36        Ok(Locker::new(CallSnapshot {
37            parent: Some(parent.clone()),
38            expression: exp.clone(),
39            depth,
40        }))
41    }
42
43    pub fn expression(&self) -> &'_ Expression {
44        &self.expression
45    }
46}
47
48impl fmt::Display for CallSnapshot {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        match &self.parent {
51            Some(parent_ref) => match parent_ref.read() {
52                // This crazy match makes sure we don't print redundant lines
53                Ok(parent) => {
54                    match format!("{}", self.expression) == format!("{}", parent.expression) {
55                        true => match &parent.parent {
56                            Some(superparent_ref) => {
57                                if let Ok(superparent) = superparent_ref.read() {
58                                    write!(f, "{}", superparent)?
59                                }
60                            }
61                            None => {}
62                        },
63                        false => write!(f, "{}", parent)?,
64                    }
65                }
66                Err(_) => writeln!(
67                    f,
68                    "      {} unable to access parent call (are threads locked?)",
69                    Color::Yellow.bold().paint("!")
70                )?,
71            },
72            None => {}
73        };
74        match self.expression().source() {
75            Some(source) => write!(f, "{}", source)?,
76            None => {}
77        }
78        write!(f, "")
79    }
80}