anathema_value_resolver/
scope.rs

1use anathema_state::{PendingValue, StateId};
2use anathema_store::slab::Key;
3
4use crate::expression::{Kind, ValueExpr};
5use crate::{Collection, ValueKind};
6
7#[derive(Debug)]
8pub(crate) enum Entry<'parent, 'bp> {
9    Component { state: StateId, component_attributes: Key },
10    Collection(&'parent Collection<'bp>),
11    Index(&'bp str, usize, PendingValue),
12    Empty,
13}
14
15#[derive(Debug)]
16pub struct Scope<'parent, 'bp> {
17    outer: Option<&'parent Scope<'parent, 'bp>>,
18    parent: Option<&'parent Scope<'parent, 'bp>>,
19    value: Entry<'parent, 'bp>,
20}
21
22impl<'parent, 'bp> Scope<'parent, 'bp> {
23    fn new(value: Entry<'parent, 'bp>) -> Self {
24        Self {
25            parent: None,
26            outer: None,
27            value,
28        }
29    }
30
31    pub fn with_component(state: StateId, attributes: Key, outer: Option<&'parent Scope<'parent, 'bp>>) -> Self {
32        Self {
33            outer,
34            parent: None,
35            value: Entry::Component {
36                state,
37                component_attributes: attributes,
38            },
39        }
40    }
41
42    pub fn with_collection(collection: &'parent Collection<'bp>, parent: &'parent Scope<'parent, 'bp>) -> Self {
43        let value = Entry::Collection(collection);
44        Self {
45            outer: None,
46            parent: Some(parent),
47            value,
48        }
49    }
50
51    pub fn with_index(
52        binding: &'bp str,
53        index: usize,
54        parent: &'parent Scope<'parent, 'bp>,
55        loop_index: PendingValue,
56    ) -> Self {
57        let value = Entry::Index(binding, index, loop_index);
58        Self {
59            value,
60            parent: Some(parent),
61            outer: None,
62        }
63    }
64
65    pub fn root() -> Self {
66        Self::empty()
67    }
68
69    pub fn empty() -> Self {
70        Self::new(Entry::Empty)
71    }
72
73    pub(crate) fn get_state(&self) -> Option<StateId> {
74        match &self.value {
75            Entry::Component { state, .. } => Some(*state),
76            _ => self.parent?.get_state(),
77        }
78    }
79
80    pub(crate) fn get_attributes(&self) -> Option<Key> {
81        match &self.value {
82            Entry::Component {
83                component_attributes, ..
84            } => Some(*component_attributes),
85            _ => self.parent?.get_attributes(),
86        }
87    }
88
89    pub(crate) fn lookup(&self, key: &str) -> Option<ValueExpr<'bp>> {
90        match self.value {
91            Entry::Index(_, _, loop_index) if key == "loop" => Some(ValueExpr::Int(Kind::Dyn(loop_index))),
92            Entry::Index(binding, index, _) if key == binding => {
93                match self.parent.expect("the parent can only be a collection").value {
94                    Entry::Collection(collection) => match &collection.0.kind {
95                        ValueKind::List(_) => {
96                            let value_expr = ValueExpr::Index(
97                                collection.0.expr.clone().into(),
98                                ValueExpr::Int(Kind::Static(index as i64)).into(),
99                            );
100                            Some(value_expr)
101                        }
102                        ValueKind::DynList(value) => {
103                            let state = value.as_state()?;
104                            let list = state.as_any_list()?;
105                            let value = list.lookup(index)?;
106                            Some(value.into())
107                        }
108                        _ => unreachable!("none of the other values can be a collection"),
109                    },
110                    _ => unreachable!("the parent scope is always a collection"),
111                }
112            }
113            _ => self.parent?.lookup(key),
114        }
115    }
116
117    /// Get the outer scope
118    ///
119    /// # Panics
120    ///
121    /// This will panic if the outer scope has been set incorrectly
122    /// or there is no parent scope.
123    pub fn outer(&self) -> &'parent Scope<'parent, 'bp> {
124        match self.outer {
125            Some(scope) => scope,
126            None => match self.parent {
127                Some(parent) => parent.outer(),
128                None => panic!("no outer scope, no parent"),
129            },
130        }
131    }
132}
133
134#[cfg(test)]
135mod test {
136
137    #[test]
138    fn scope_one() {
139        // let mut scope = Scope::new();
140        // panic!();
141        // scope.scope("key",
142    }
143}