anathema_value_resolver/
scope.rs1use 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 _ => unreachable!("none of the other values can be a collection"),
120 },
121 _ => unreachable!("the parent scope is always a collection"),
122 }
123 }
124 _ => self.parent?.lookup(key),
125 }
126 }
127
128 pub fn outer(&self) -> &'parent Scope<'parent, 'bp> {
135 match self.outer {
136 Some(scope) => scope,
137 None => match self.parent {
138 Some(parent) => parent.outer(),
139 None => panic!("no outer scope, no parent"),
140 },
141 }
142 }
143}
144
145#[cfg(test)]
146mod test {
147
148 #[test]
149 fn scope_one() {
150 }
154}