Skip to main content

anathema_value_resolver/
scope.rs

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