1use super::*;
2use std::collections::VecDeque;
3
4pub(super) fn evaluate_bool(expr: &Expression, ctx: &Context) -> EvalResult<bool> {
5 match expr.evaluate(ctx)? {
6 Value::Bool(value) => Ok(value),
7 other => Err(ctx.error(Error::unexpected(other, "a boolean"))),
8 }
9}
10
11pub(super) fn evaluate_object_key(expr: &Expression, ctx: &Context) -> EvalResult<String> {
15 match expr.evaluate(ctx)? {
16 Value::String(value) => Ok(value),
17 Value::Bool(value) => Ok(value.to_string()),
18 Value::Number(value) => Ok(value.to_string()),
19 other => Err(ctx.error(Error::unexpected(other, "a string, boolean or number"))),
20 }
21}
22
23pub(super) fn evaluate_array(expr: &Expression, ctx: &Context) -> EvalResult<Vec<Value>> {
24 match expr.evaluate(ctx)? {
25 Value::Array(array) => Ok(array),
26 other => Err(ctx.error(Error::unexpected(other, "an array"))),
27 }
28}
29
30pub(super) fn evaluate_traversal(
31 mut value: Value,
32 mut operators: VecDeque<&TraversalOperator>,
33 ctx: &Context,
34) -> EvalResult<Value> {
35 while let Some(operator) = operators.pop_front() {
36 value = match operator {
37 TraversalOperator::LegacyIndex(index) => {
38 evaluate_array_value(value, *index as usize, ctx)?
39 }
40 TraversalOperator::Index(index_expr) => evaluate_index_expr(value, index_expr, ctx)?,
41 TraversalOperator::GetAttr(name) => evaluate_object_value(value, name, ctx)?,
42 TraversalOperator::AttrSplat => {
43 let mut remaining = VecDeque::with_capacity(operators.len());
46
47 while let Some(operator) = operators.pop_front() {
48 match operator {
49 TraversalOperator::GetAttr(_) => remaining.push_back(operator),
50 other => {
51 operators.push_front(other);
52 break;
53 }
54 }
55 }
56
57 evaluate_splat(value, remaining, ctx)?
58 }
59 TraversalOperator::FullSplat => {
60 let remaining: VecDeque<&TraversalOperator> = std::mem::take(&mut operators);
62
63 evaluate_splat(value, remaining, ctx)?
64 }
65 }
66 }
67
68 Ok(value)
69}
70
71fn evaluate_splat(
72 value: Value,
73 operators: VecDeque<&TraversalOperator>,
74 ctx: &Context,
75) -> EvalResult<Value> {
76 let array = match value {
77 Value::Array(array) => array
78 .into_iter()
79 .map(|value| evaluate_traversal(value, operators.clone(), ctx))
80 .collect::<EvalResult<_>>()?,
81 Value::Null => vec![],
82 other => evaluate_traversal(other, operators, ctx).map(|expr| vec![expr])?,
83 };
84
85 Ok(Value::Array(array))
86}
87
88fn evaluate_index_expr(value: Value, index_expr: &Expression, ctx: &Context) -> EvalResult<Value> {
89 match index_expr.evaluate(ctx)? {
90 Value::String(name) => evaluate_object_value(value, &name, ctx),
91 Value::Number(num) => match num.as_u64() {
92 Some(index) => evaluate_array_value(value, index as usize, ctx),
93 None => Err(ctx.error(Error::unexpected(num, "an unsigned integer"))),
94 },
95 other => Err(ctx.error(Error::unexpected(other, "an unsigned integer or string"))),
96 }
97}
98
99fn evaluate_array_value(mut value: Value, index: usize, ctx: &Context) -> EvalResult<Value> {
100 match value.as_array_mut() {
101 Some(array) => {
102 if index < array.len() {
103 Ok(array.swap_remove(index))
104 } else {
105 Err(ctx.error(ErrorKind::Index(index)))
106 }
107 }
108 None => Err(ctx.error(Error::unexpected(value, "an array"))),
109 }
110}
111
112fn evaluate_object_value(mut value: Value, key: &str, ctx: &Context) -> EvalResult<Value> {
113 match value.as_object_mut() {
114 Some(object) => object
115 .swap_remove(key)
116 .ok_or_else(|| ctx.error(ErrorKind::NoSuchKey(key.to_string()))),
117 None => Err(ctx.error(Error::unexpected(value, "an object"))),
118 }
119}
120
121fn evaluate_collection(expr: &Expression, ctx: &Context) -> EvalResult<Vec<(Value, Value)>> {
122 match expr.evaluate(ctx)? {
123 Value::Array(array) => Ok(array
124 .into_iter()
125 .enumerate()
126 .map(|(index, value)| (Value::from(index), value))
127 .collect()),
128 Value::Object(object) => Ok(object
129 .into_iter()
130 .map(|(key, value)| (Value::from(key), value))
131 .collect()),
132 other => Err(ctx.error(Error::unexpected(other, "an array or object"))),
133 }
134}
135
136pub(super) struct Collection<'a> {
137 ctx: &'a Context<'a>,
138 key_var: Option<&'a Identifier>,
139 value_var: &'a Identifier,
140 cond_expr: Option<&'a Expression>,
141 #[allow(clippy::struct_field_names)]
142 collection: Vec<(Value, Value)>,
143}
144
145impl<'a> Collection<'a> {
146 pub(super) fn from_for_expr(for_expr: &'a ForExpr, ctx: &'a Context<'a>) -> EvalResult<Self> {
147 Ok(Collection {
148 ctx,
149 key_var: for_expr.key_var.as_ref(),
150 value_var: &for_expr.value_var,
151 cond_expr: for_expr.cond_expr.as_ref(),
152 collection: evaluate_collection(&for_expr.collection_expr, ctx)?,
153 })
154 }
155
156 pub(super) fn from_for_directive(
157 for_directive: &'a ForDirective,
158 ctx: &'a Context<'a>,
159 ) -> EvalResult<Self> {
160 Ok(Collection {
161 ctx,
162 key_var: for_directive.key_var.as_ref(),
163 value_var: &for_directive.value_var,
164 cond_expr: None,
165 collection: evaluate_collection(&for_directive.collection_expr, ctx)?,
166 })
167 }
168
169 pub(super) fn len(&self) -> usize {
170 self.collection.len()
171 }
172}
173
174impl<'a> IntoIterator for Collection<'a> {
175 type Item = EvalResult<Context<'a>>;
176 type IntoIter = IntoIter<'a>;
177
178 fn into_iter(self) -> Self::IntoIter {
179 IntoIter {
180 ctx: self.ctx,
181 key_var: self.key_var,
182 value_var: self.value_var,
183 cond_expr: self.cond_expr,
184 iter: self.collection.into_iter(),
185 }
186 }
187}
188
189pub(super) struct IntoIter<'a> {
190 ctx: &'a Context<'a>,
191 key_var: Option<&'a Identifier>,
192 value_var: &'a Identifier,
193 cond_expr: Option<&'a Expression>,
194 iter: std::vec::IntoIter<(Value, Value)>,
195}
196
197impl<'a> IntoIter<'a> {
198 fn cond(&self, ctx: &Context) -> EvalResult<bool> {
199 match &self.cond_expr {
200 None => Ok(true),
201 Some(cond_expr) => evaluate_bool(cond_expr, ctx),
202 }
203 }
204
205 fn next_ctx(&mut self) -> Option<Context<'a>> {
206 let (key, value) = self.iter.next()?;
207 let mut ctx = self.ctx.child();
208 if let Some(key_var) = self.key_var {
209 ctx.declare_var(key_var.clone(), key);
210 }
211
212 ctx.declare_var(self.value_var.clone(), value);
213 Some(ctx)
214 }
215}
216
217impl<'a> Iterator for IntoIter<'a> {
218 type Item = EvalResult<Context<'a>>;
219
220 fn next(&mut self) -> Option<Self::Item> {
221 loop {
222 let ctx = self.next_ctx()?;
223
224 match self.cond(&ctx) {
225 Ok(false) => {}
226 Ok(true) => return Some(Ok(ctx)),
227 Err(err) => return Some(Err(err)),
228 }
229 }
230 }
231}