rimu_eval/
expression.rs

1// with help from
2// - https://github.com/DennisPrediger/SLAC/blob/main/src/interpreter.rs
3
4use rimu_ast::{BinaryOperator, Expression, SpannedExpression, UnaryOperator};
5use rimu_meta::{Span, Spanned};
6use rimu_value::{
7    convert_value_object_to_serde_value_object, Environment, Function, FunctionBody, Number,
8    SpannedValue, Value, ValueObject,
9};
10use rust_decimal::prelude::ToPrimitive;
11use std::{cell::RefCell, ops::Deref, rc::Rc};
12
13use crate::{common, EvalError, Result};
14
15pub fn evaluate(
16    expression: &SpannedExpression,
17    env: Rc<RefCell<Environment>>,
18) -> Result<SpannedValue> {
19    Evaluator::new(env).expression(expression)
20}
21
22/// A tree walking interpreter which given an [`Environment`] and an [`Expression`]
23/// recursivly walks the tree and computes a single [`Value`].
24struct Evaluator {
25    env: Rc<RefCell<Environment>>,
26}
27
28impl Evaluator {
29    fn new(env: Rc<RefCell<Environment>>) -> Self {
30        Self { env }
31    }
32
33    fn expression(&self, expr: &SpannedExpression) -> Result<SpannedValue> {
34        let span = expr.span();
35        match expr.inner() {
36            Expression::Null => Ok(Spanned::new(Value::Null, span)),
37
38            Expression::Boolean(boolean) => Ok(Spanned::new(Value::Boolean(*boolean), span)),
39
40            Expression::String(string) => self.string(span, string),
41
42            Expression::Number(decimal) => Ok(Spanned::new(
43                Value::Number(Into::<Number>::into(*decimal)),
44                span,
45            )),
46
47            Expression::List(ref items) => self.list(span, items),
48
49            Expression::Object(ref entries) => self.object(span, entries),
50
51            Expression::Function { ref args, ref body } => self.function(span, args, body),
52
53            Expression::Identifier(var) => self.variable(span, var),
54
55            Expression::Unary {
56                ref right,
57                ref operator,
58            } => self.unary(span, right, operator),
59
60            Expression::Binary {
61                ref left,
62                ref right,
63                ref operator,
64            } => self.binary(span, left, operator, right),
65
66            Expression::Call {
67                ref function,
68                ref args,
69            } => self.call(span, function, args),
70
71            Expression::GetIndex { container, index } => self.get_index(span, container, index),
72
73            Expression::GetKey { container, key } => self.get_key(span, container, key),
74
75            Expression::GetSlice {
76                container,
77                ref start,
78                ref end,
79            } => self.get_slice(
80                span,
81                container,
82                start.as_ref().map(|s| s.deref()),
83                end.as_ref().map(|e| e.deref()),
84            ),
85
86            Expression::Error => Err(EvalError::ErrorExpression { span }),
87        }
88    }
89
90    fn string(&self, span: Span, string: &str) -> Result<SpannedValue> {
91        // TODO handle string interpolations
92        let value = Value::String(string.to_string());
93        Ok(Spanned::new(value, span))
94    }
95
96    fn function(
97        &self,
98        span: Span,
99        args: &[Spanned<String>],
100        body: &SpannedExpression,
101    ) -> Result<SpannedValue> {
102        let args: Vec<String> = args.iter().map(|a| a.inner()).cloned().collect();
103        let body = FunctionBody::Expression(body.clone());
104        let env = self.env.clone();
105        let value = Value::Function(Function { args, body, env });
106        Ok(Spanned::new(value, span))
107    }
108
109    fn unary(
110        &self,
111        span: Span,
112        right: &SpannedExpression,
113        operator: &UnaryOperator,
114    ) -> Result<SpannedValue> {
115        let (right, right_span) = self.expression(right)?.take();
116        let value = match operator {
117            UnaryOperator::Negate => match right.clone() {
118                Value::Number(number) => Ok(Value::Number(-number)),
119                _ => Err(EvalError::TypeError {
120                    span: right_span,
121                    expected: "number".into(),
122                    got: right.clone().into(),
123                }),
124            },
125            UnaryOperator::Not => {
126                let boolean: bool = right.into();
127                Ok(Value::Boolean(!boolean))
128            }
129        }?;
130        Ok(Spanned::new(value, span))
131    }
132
133    fn binary(
134        &self,
135        span: Span,
136        left: &SpannedExpression,
137        operator: &BinaryOperator,
138        right: &SpannedExpression,
139    ) -> Result<SpannedValue> {
140        let (left, left_span) = self.expression(left)?.take();
141        match operator {
142            BinaryOperator::And => self.boolean(span, left, right, true),
143            BinaryOperator::Or => self.boolean(span, left, right, false),
144            _ => {
145                let (right, right_span) = self.expression(right)?.take();
146                let value = match operator {
147                    BinaryOperator::Or => unreachable!(),
148                    BinaryOperator::And => unreachable!(),
149                    BinaryOperator::Add => match (left.clone(), right.clone()) {
150                        (Value::Number(left), Value::Number(right)) => {
151                            Ok(Value::Number(left + right))
152                        }
153                        (Value::Number(_left), right) => Err(EvalError::TypeError {
154                            span: right_span,
155                            expected: "number".into(),
156                            got: right.into(),
157                        }),
158                        (Value::String(left), Value::String(right)) => {
159                            Ok(Value::String([left, right].join("")))
160                        }
161                        (Value::String(_left), right) => Err(EvalError::TypeError {
162                            span: right_span,
163                            expected: "string".into(),
164                            got: right.into(),
165                        }),
166                        (Value::List(left), Value::List(right)) => {
167                            Ok(Value::List([left, right].concat()))
168                        }
169                        (Value::List(_left), right) => Err(EvalError::TypeError {
170                            span: right_span,
171                            expected: "list".into(),
172                            got: right.into(),
173                        }),
174                        _ => Err(EvalError::TypeError {
175                            span: left_span,
176                            expected: "number | string | list".into(),
177                            got: left.into(),
178                        }),
179                    },
180                    BinaryOperator::Subtract => match (left.clone(), right.clone()) {
181                        (Value::Number(left), Value::Number(right)) => {
182                            Ok(Value::Number(left - right))
183                        }
184                        (Value::Number(_left), right) => Err(EvalError::TypeError {
185                            span: right_span,
186                            expected: "number".into(),
187                            got: right.into(),
188                        }),
189                        _ => Err(EvalError::TypeError {
190                            span: left_span,
191                            expected: "number".into(),
192                            got: left.into(),
193                        }),
194                    },
195                    BinaryOperator::Multiply => match (left.clone(), right.clone()) {
196                        (Value::Number(left), Value::Number(right)) => {
197                            Ok(Value::Number(left * right))
198                        }
199                        (Value::Number(_left), right) => Err(EvalError::TypeError {
200                            span: right_span,
201                            expected: "number".into(),
202                            got: right.into(),
203                        }),
204                        _ => Err(EvalError::TypeError {
205                            span: left_span,
206                            expected: "number".into(),
207                            got: left.into(),
208                        }),
209                    },
210                    BinaryOperator::Divide => match (left.clone(), right.clone()) {
211                        (Value::Number(left), Value::Number(right)) => {
212                            Ok(Value::Number(left / right))
213                        }
214                        (Value::Number(_left), right) => Err(EvalError::TypeError {
215                            span: right_span,
216                            expected: "number".into(),
217                            got: right.into(),
218                        }),
219                        _ => Err(EvalError::TypeError {
220                            span: left_span,
221                            expected: "number".into(),
222                            got: left.into(),
223                        }),
224                    },
225                    BinaryOperator::Rem => match (left.clone(), right.clone()) {
226                        (Value::Number(left), Value::Number(right)) => {
227                            Ok(Value::Number(left % right))
228                        }
229                        (Value::Number(_left), right) => Err(EvalError::TypeError {
230                            span: right_span,
231                            expected: "number".into(),
232                            got: right.into(),
233                        }),
234                        _ => Err(EvalError::TypeError {
235                            span: left_span,
236                            expected: "number".into(),
237                            got: left.into(),
238                        }),
239                    },
240                    BinaryOperator::Xor => match (left.clone(), right.clone()) {
241                        (Value::Boolean(left), Value::Boolean(right)) => {
242                            Ok(Value::Boolean(left ^ right))
243                        }
244                        (Value::Boolean(_left), right) => Err(EvalError::TypeError {
245                            span: right_span,
246                            expected: "boolean".into(),
247                            got: right.into(),
248                        }),
249                        _ => Err(EvalError::TypeError {
250                            span: left_span,
251                            expected: "boolean".into(),
252                            got: left.into(),
253                        }),
254                    },
255                    BinaryOperator::Greater => match (left.clone(), right.clone()) {
256                        (Value::Number(left), Value::Number(right)) => {
257                            Ok(Value::Boolean(left > right))
258                        }
259                        (Value::Number(_left), right) => Err(EvalError::TypeError {
260                            span: right_span,
261                            expected: "number".into(),
262                            got: right.into(),
263                        }),
264                        _ => Err(EvalError::TypeError {
265                            span: left_span,
266                            expected: "number".into(),
267                            got: left.into(),
268                        }),
269                    },
270                    BinaryOperator::GreaterEqual => match (left.clone(), right.clone()) {
271                        (Value::Number(left), Value::Number(right)) => {
272                            Ok(Value::Boolean(left >= right))
273                        }
274                        (Value::Number(_left), right) => Err(EvalError::TypeError {
275                            span: right_span,
276                            expected: "number".into(),
277                            got: right.into(),
278                        }),
279                        _ => Err(EvalError::TypeError {
280                            span: left_span,
281                            expected: "number".into(),
282                            got: left.into(),
283                        }),
284                    },
285                    BinaryOperator::Less => match (left.clone(), right.clone()) {
286                        (Value::Number(left), Value::Number(right)) => {
287                            Ok(Value::Boolean(left < right))
288                        }
289                        (Value::Number(_left), right) => Err(EvalError::TypeError {
290                            span: right_span,
291                            expected: "number".into(),
292                            got: right.into(),
293                        }),
294                        _ => Err(EvalError::TypeError {
295                            span: left_span,
296                            expected: "number".into(),
297                            got: left.into(),
298                        }),
299                    },
300                    BinaryOperator::LessEqual => match (left.clone(), right.clone()) {
301                        (Value::Number(left), Value::Number(right)) => {
302                            Ok(Value::Boolean(left <= right))
303                        }
304                        (Value::Number(_left), right) => Err(EvalError::TypeError {
305                            span: right_span,
306                            expected: "number".into(),
307                            got: right.into(),
308                        }),
309                        _ => Err(EvalError::TypeError {
310                            span: left_span,
311                            expected: "number".into(),
312                            got: left.into(),
313                        }),
314                    },
315                    BinaryOperator::Equal => Ok(Value::Boolean(left == right)),
316                    BinaryOperator::NotEqual => Ok(Value::Boolean(left != right)),
317                }?;
318                Ok(Spanned::new(value, span))
319            }
320        }
321    }
322
323    fn boolean(
324        &self,
325        span: Span,
326        left: Value,
327        right: &SpannedExpression,
328        full_evaluate_on: bool,
329    ) -> Result<SpannedValue> {
330        let left: bool = left.into();
331        let value = if left == full_evaluate_on {
332            // if `left` is not the result we need, evaluate `right`
333            let right = self.expression(right)?.into_inner();
334            let right: bool = right.into();
335            Value::Boolean(right)
336        } else {
337            Value::Boolean(left) // short circuit
338        };
339        Ok(Spanned::new(value, span))
340    }
341
342    fn list(&self, span: Span, items: &Vec<SpannedExpression>) -> Result<SpannedValue> {
343        let mut next_items = Vec::with_capacity(items.len());
344        for item in items {
345            let next_item = self.expression(item)?;
346            next_items.push(next_item);
347        }
348        let value = Value::List(next_items);
349        Ok(Spanned::new(value, span))
350    }
351
352    fn object(
353        &self,
354        span: Span,
355        entries: &[(Spanned<String>, SpannedExpression)],
356    ) -> Result<SpannedValue> {
357        let mut object = ValueObject::new();
358        for (key, value) in entries.iter() {
359            let key = key.clone().into_inner();
360            let value = self.expression(value)?;
361            object.insert(key, value);
362        }
363        let value = Value::Object(object);
364        Ok(Spanned::new(value, span))
365    }
366
367    fn variable(&self, span: Span, var: &str) -> Result<SpannedValue> {
368        let value = self
369            .env
370            .borrow()
371            .get(var)
372            .ok_or_else(|| EvalError::MissingVariable {
373                span: span.clone(),
374                var: var.to_string(),
375            })?;
376        Ok(value.with_span(span))
377    }
378
379    fn call(
380        &self,
381        span: Span,
382        function: &SpannedExpression,
383        args: &[SpannedExpression],
384    ) -> Result<SpannedValue> {
385        let Value::Function(function) = self.expression(function)?.into_inner() else {
386            return Err(EvalError::CallNonFunction {
387                span: function.span(),
388                expr: function.clone().into_inner(),
389            });
390        };
391
392        let args: Vec<SpannedValue> = args
393            .iter()
394            .map(|expression| self.expression(expression))
395            .collect::<Result<Vec<SpannedValue>>>()?;
396
397        common::call(span, function, &args)
398    }
399
400    fn get_index(
401        &self,
402        span: Span,
403        container: &SpannedExpression,
404        index: &SpannedExpression,
405    ) -> Result<SpannedValue> {
406        let (container, container_span) = self.expression(container)?.take();
407        let (index, index_span) = self.expression(index)?.take();
408
409        let value = match (container.clone(), index.clone()) {
410            (Value::List(list), index_value) => {
411                let index = get_index(container_span, index_span, index_value, list.len(), false)?;
412                list[index as usize].clone()
413            }
414            (Value::String(string), index_value) => {
415                let index =
416                    get_index(container_span, index_span, index_value, string.len(), false)?;
417                let ch = string[index as usize..].chars().next().unwrap();
418                Spanned::new(Value::String(ch.into()), span.clone())
419            }
420            (Value::Object(object), Value::String(key)) => object
421                .get(&key)
422                .map(Clone::clone)
423                .ok_or_else(|| EvalError::KeyNotFound {
424                    object_span: container_span,
425                    object: convert_value_object_to_serde_value_object(object),
426                    key_span: index_span,
427                    key: key.clone(),
428                })?,
429            (Value::Object(_list), _) => {
430                return Err(EvalError::TypeError {
431                    span: index_span,
432                    expected: "string".into(),
433                    got: index.into(),
434                })
435            }
436            _ => {
437                return Err(EvalError::TypeError {
438                    span: container_span,
439                    expected: "list | string | object".into(),
440                    got: container.into(),
441                })
442            }
443        };
444
445        Ok(Spanned::new(value.into_inner(), span))
446    }
447
448    fn get_key(
449        &self,
450        span: Span,
451        container: &SpannedExpression,
452        key: &Spanned<String>,
453    ) -> Result<SpannedValue> {
454        let (container, container_span) = self.expression(container)?.take();
455
456        let Value::Object(object) = container.clone() else {
457            return Err(EvalError::TypeError {
458                span: container_span,
459                expected: "object".into(),
460                got: container.into(),
461            });
462        };
463
464        let value = object
465            .get(key.inner())
466            .ok_or_else(|| EvalError::KeyNotFound {
467                object_span: container_span,
468                object: convert_value_object_to_serde_value_object(object.clone()),
469                key: key.clone().into_inner(),
470                key_span: key.span(),
471            })
472            .map(Clone::clone)?;
473
474        Ok(Spanned::new(value.into_inner(), span))
475    }
476
477    fn get_slice(
478        &self,
479        span: Span,
480        container: &SpannedExpression,
481        start: Option<&SpannedExpression>,
482        end: Option<&SpannedExpression>,
483    ) -> Result<SpannedValue> {
484        let (container, container_span) = self.expression(container)?.take();
485        let start = match start {
486            Some(start) => Some(self.expression(start)?.take()),
487            None => None,
488        };
489        let end = match end {
490            Some(end) => Some(self.expression(end)?.take()),
491            None => None,
492        };
493
494        let value = match container.clone() {
495            Value::List(list) => {
496                let length = list.len();
497                match (start.clone(), end.clone()) {
498                    (None, None) => Value::List(list),
499                    (Some((start, start_span)), None) => {
500                        let start = get_index(container_span, start_span, start, length, false)?;
501                        Value::List(list[start..].to_vec())
502                    }
503                    (None, Some((end, end_span))) => {
504                        let end = get_index(container_span, end_span, end, length, true)?;
505                        Value::List(list[..end].to_vec())
506                    }
507                    (Some((start, start_span)), Some((end, end_span))) => {
508                        let start =
509                            get_index(container_span.clone(), start_span, start, length, false)?;
510                        let end = get_index(container_span.clone(), end_span, end, length, true)?;
511                        if start >= end {
512                            return Err(EvalError::RangeStartGreaterThanOrEqualToEnd {
513                                span,
514                                start,
515                                end,
516                            });
517                        }
518                        Value::List(list[start..end].to_vec())
519                    }
520                }
521            }
522            Value::String(string) => {
523                let length = string.len();
524                match (start.clone(), end.clone()) {
525                    (None, None) => Value::String(string),
526                    (Some((start, start_span)), None) => {
527                        let start = get_index(container_span, start_span, start, length, false)?;
528                        Value::String(string[start..].to_string())
529                    }
530                    (None, Some((end, end_span))) => {
531                        let end = get_index(container_span, end_span, end, length, true)?;
532                        Value::String(string[..end].to_string())
533                    }
534                    (Some((start, start_span)), Some((end, end_span))) => {
535                        let start =
536                            get_index(container_span.clone(), start_span, start, length, false)?;
537                        let end = get_index(container_span.clone(), end_span, end, length, true)?;
538                        if start >= end {
539                            return Err(EvalError::RangeStartGreaterThanOrEqualToEnd {
540                                span,
541                                start,
542                                end,
543                            });
544                        }
545                        Value::String(string[start..end].to_string())
546                    }
547                }
548            }
549            _ => {
550                return Err(EvalError::TypeError {
551                    span: container_span,
552                    expected: "list".into(),
553                    got: container.into(),
554                })
555            }
556        };
557
558        Ok(Spanned::new(value, span))
559    }
560}
561
562fn get_index(
563    container_span: Span,
564    value_span: Span,
565    value: Value,
566    length: usize,
567    is_range_end: bool,
568) -> Result<usize> {
569    let Value::Number(number) = value else {
570        return Err(EvalError::TypeError {
571            span: value_span,
572            expected: "number".into(),
573            got: value.into(),
574        });
575    };
576    let number = if number.is_integer() {
577        number.to_isize()
578    } else {
579        None
580    };
581    let Some(mut index) = number else {
582        return Err(EvalError::TypeError {
583            span: value_span,
584            expected: "integer".into(),
585            got: value.into(),
586        });
587    };
588    let is_under = index <= -(length as isize);
589    let is_over = if !is_range_end {
590        index >= length as isize
591    } else {
592        index > length as isize
593    };
594    if is_under || is_over {
595        return Err(EvalError::IndexOutOfBounds {
596            container_span,
597            index_span: value_span,
598            index,
599            length,
600        });
601    }
602    // handle negative indices
603    if index < 0 {
604        index += length as isize
605    }
606    Ok(index as usize)
607}
608
609#[cfg(test)]
610mod tests {
611    use indexmap::IndexMap;
612    use std::{cell::RefCell, ops::Range, rc::Rc};
613
614    use indexmap::indexmap;
615    use pretty_assertions::assert_eq;
616    use rimu_ast::{BinaryOperator, Expression, SpannedExpression};
617    use rimu_meta::{SourceId, Span, Spanned};
618    use rimu_parse::parse_expression;
619    use rimu_value::{Environment, Function, FunctionBody, SerdeValue};
620    use rust_decimal_macros::dec;
621
622    use super::{evaluate, EvalError};
623
624    fn span(range: Range<usize>) -> Span {
625        Span::new(SourceId::empty(), range.start, range.end)
626    }
627
628    fn test_expression(
629        expr: SpannedExpression,
630        env_object: Option<IndexMap<String, SerdeValue>>,
631    ) -> Result<SerdeValue, EvalError> {
632        let mut env = Environment::new();
633        if let Some(env_object) = env_object {
634            for (key, value) in env_object.into_iter() {
635                env.insert(key, value);
636            }
637        }
638
639        let value = evaluate(&expr, Rc::new(RefCell::new(env)))?;
640        let value: SerdeValue = value.into();
641        Ok(value)
642    }
643
644    fn test_code(
645        code: &str,
646        env_object: Option<IndexMap<String, SerdeValue>>,
647    ) -> Result<SerdeValue, EvalError> {
648        let (Some(expr), errors) = parse_expression(code, SourceId::empty()) else {
649            panic!()
650        };
651        assert_eq!(errors.len(), 0);
652        test_expression(expr, env_object)
653    }
654
655    #[test]
656    fn simple_null() {
657        let expr = Spanned::new(Expression::Null, span(0..1));
658        let actual = test_expression(expr, None);
659
660        let expected = Ok(SerdeValue::Null);
661
662        assert_eq!(actual, expected);
663    }
664
665    #[test]
666    fn simple_bool() {
667        let expr = Spanned::new(Expression::Boolean(false), span(0..1));
668        let actual = test_expression(expr, None);
669
670        let expected = Ok(SerdeValue::Boolean(false));
671
672        assert_eq!(actual, expected);
673    }
674
675    #[test]
676    fn simple_number() {
677        let number = dec!(9001);
678        let expr = Spanned::new(Expression::Number(number), span(0..1));
679        let actual = test_expression(expr, None);
680
681        let expected = Ok(SerdeValue::Number(number.into()));
682
683        assert_eq!(actual, expected);
684    }
685
686    #[test]
687    fn simple_list() {
688        let expr = Spanned::new(
689            Expression::List(vec![
690                Spanned::new(Expression::String("hello".into()), span(1..2)),
691                Spanned::new(Expression::Boolean(true), span(3..4)),
692                Spanned::new(Expression::String("world".into()), span(5..6)),
693            ]),
694            span(0..8),
695        );
696        let actual = test_expression(expr, None);
697
698        let expected = Ok(SerdeValue::List(vec![
699            SerdeValue::String("hello".into()),
700            SerdeValue::Boolean(true),
701            SerdeValue::String("world".into()),
702        ]));
703
704        assert_eq!(actual, expected);
705    }
706
707    #[test]
708    fn simple_object() {
709        let expr = Spanned::new(
710            Expression::Object(vec![
711                (
712                    Spanned::new("a".into(), span(1..2)),
713                    Spanned::new(Expression::String("hello".into()), span(3..4)),
714                ),
715                (
716                    Spanned::new("b".into(), span(5..6)),
717                    Spanned::new(Expression::String("world".into()), span(7..8)),
718                ),
719            ]),
720            span(0..10),
721        );
722        let actual = test_expression(expr, None);
723
724        let expected = Ok(SerdeValue::Object(indexmap! {
725            "a".into() => "hello".into(),
726            "b".into() => "world".into(),
727        }));
728
729        assert_eq!(actual, expected);
730    }
731
732    #[test]
733    fn simple_function_call() {
734        let env = indexmap! {
735            "add".into() => SerdeValue::Function(Function {
736                args: vec!["a".into(), "b".into()],
737                body: FunctionBody::Expression(Spanned::new(
738                    Expression::Binary {
739                        left: Box::new(Spanned::new(
740                            Expression::Identifier("a".into()),
741                            span(0..1),
742                        )),
743                        operator: BinaryOperator::Add,
744                        right: Box::new(Spanned::new(
745                            Expression::Identifier("b".into()),
746                            span(2..3),
747                        )),
748                    },
749                    span(0..3),
750                )),
751                env: Rc::new(RefCell::new(Environment::new())),
752            }),
753            "one".into() => SerdeValue::Number(dec!(1).into()),
754            "two".into() => SerdeValue::Number(dec!(2).into()),
755        };
756
757        let expr = Spanned::new(
758            Expression::Call {
759                function: Box::new(Spanned::new(
760                    Expression::Identifier("add".into()),
761                    span(0..1),
762                )),
763                args: vec![
764                    Spanned::new(Expression::Identifier("one".into()), span(2..3)),
765                    Spanned::new(Expression::Identifier("two".into()), span(4..5)),
766                ],
767            },
768            span(0..7),
769        );
770
771        let actual = test_expression(expr, Some(env));
772
773        let expected = Ok(SerdeValue::Number(dec!(3).into()));
774
775        assert_eq!(actual, expected);
776    }
777
778    #[test]
779    fn arithmetic() {
780        let env = indexmap! {
781            "x".into() => SerdeValue::Number(dec!(10).into()),
782            "y".into() => SerdeValue::Number(dec!(20).into()),
783            "z".into() => SerdeValue::Number(dec!(40).into()),
784            "w".into() => SerdeValue::Number(dec!(80).into()),
785        };
786        let actual = test_code("x + y * (z / w)", Some(env));
787
788        let expected = Ok(SerdeValue::Number(dec!(20).into()));
789
790        assert_eq!(actual, expected);
791    }
792
793    #[test]
794    fn get_list_index() {
795        let env = indexmap! {
796            "list".into() => SerdeValue::List(vec![
797                SerdeValue::String("a".into()),
798                SerdeValue::String("b".into()),
799                SerdeValue::String("c".into()),
800                SerdeValue::String("d".into()),
801            ]),
802            // "index".into() => Value::Number(dec!(2).into()),
803        };
804        // let actual = test_code("list[index]", Some(env));
805        let actual = test_code("list[2]", Some(env));
806
807        let expected = Ok(SerdeValue::String("c".into()));
808
809        assert_eq!(actual, expected);
810    }
811
812    #[test]
813    fn get_list_index_negative() {
814        let env = indexmap! {
815            "list".into() => SerdeValue::List(vec![
816                SerdeValue::String("a".into()),
817                SerdeValue::String("b".into()),
818                SerdeValue::String("c".into()),
819                SerdeValue::String("d".into()),
820            ]),
821            // "index".into() => Value::Number(dec!(-2).into()),
822        };
823        // let actual = test_code("list[index]", Some(env));
824        let actual = test_code("list[-2]", Some(env));
825
826        let expected = Ok(SerdeValue::String("c".into()));
827
828        assert_eq!(actual, expected);
829    }
830
831    #[test]
832    fn get_key() {
833        let env = indexmap! {
834            "object".into() => SerdeValue::Object(indexmap! {
835                "a".into() => SerdeValue::String("apple".into()),
836                "b".into() => SerdeValue::String("bear".into()),
837                "c".into() => SerdeValue::String("cranberry".into()),
838                "d".into() => SerdeValue::String("dog".into()),
839            }),
840        };
841        let actual = test_code("object.a", Some(env));
842
843        let expected = Ok(SerdeValue::String("apple".into()));
844
845        assert_eq!(actual, expected);
846    }
847
848    #[test]
849    fn get_slice_start_end() {
850        let env = indexmap! {
851            "list".into() => SerdeValue::List(vec![
852                SerdeValue::String("a".into()),
853                SerdeValue::String("b".into()),
854                SerdeValue::String("c".into()),
855                SerdeValue::String("d".into()),
856                SerdeValue::String("e".into()),
857            ]),
858            "start".into() => SerdeValue::Number(dec!(1).into()),
859            "end".into() => SerdeValue::Number(dec!(3).into()),
860        };
861        let actual = test_code("list[start:end]", Some(env));
862
863        let expected = Ok(SerdeValue::List(vec![
864            SerdeValue::String("b".into()),
865            SerdeValue::String("c".into()),
866        ]));
867
868        assert_eq!(actual, expected);
869    }
870}