anathema_value_resolver/
scope.rs1use 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 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 }
143}