Skip to main content

yash_arith/
eval.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2022 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! Evaluation of the expression
18
19use crate::ast::Ast;
20use crate::ast::BinaryOperator;
21use crate::ast::PostfixOperator;
22use crate::ast::PrefixOperator;
23use crate::env::Env;
24use crate::token::Term;
25use crate::token::Value;
26use std::ops::Range;
27use thiserror::Error;
28
29/// Cause of an evaluation error
30///
31/// The type parameters `E1` and `E2` define the types of errors returned by the
32/// [`Env::get_variable`] and [`Env::assign_variable`] methods, respectively.
33#[derive(Clone, Debug, Eq, Error, Hash, PartialEq)]
34#[non_exhaustive]
35pub enum EvalError<E1, E2> {
36    /// A variable value that is not a valid number
37    #[error("invalid variable value: {0:?}")]
38    InvalidVariableValue(String),
39    /// Result out of bounds
40    #[error("overflow")]
41    Overflow,
42    /// Division by zero
43    #[error("division by zero")]
44    DivisionByZero,
45    /// Left bit-shifting with a negative left-hand-side operand
46    #[error("left-shifting a negative integer")]
47    LeftShiftingNegative,
48    /// Bit-shifting with a negative right-hand-side operand
49    #[error("negative shift width")]
50    ReverseShifting,
51    /// Assignment with a left-hand-side operand not being a variable
52    #[error("assignment to a non-variable")]
53    AssignmentToValue,
54    /// Error accessing a variable value.
55    ///
56    /// The associated value is the error returned by the [`Env::get_variable`]
57    /// method.
58    #[error(transparent)]
59    GetVariableError(E1),
60    /// Error assigning a variable value.
61    ///
62    /// The associated value is the error returned by the
63    /// [`Env::assign_variable`] method.
64    #[error(transparent)]
65    AssignVariableError(E2),
66}
67
68/// Description of an error that occurred during evaluation
69#[derive(Clone, Debug, Eq, Error, Hash, PartialEq)]
70#[error("{cause}")]
71pub struct Error<E1, E2> {
72    /// Cause of the error
73    pub cause: EvalError<E1, E2>,
74    /// Range of the substring in the evaluated expression string where the error occurred
75    pub location: Range<usize>,
76}
77
78/// Expands a variable to its value.
79fn expand_variable<E: Env>(
80    name: &str,
81    location: &Range<usize>,
82    env: &E,
83) -> Result<Value, Error<E::GetVariableError, E::AssignVariableError>> {
84    match env.get_variable(name) {
85        Ok(None) => Ok(Value::Integer(0)),
86        // TODO Parse non-decimal integer and float
87        Ok(Some(value)) => match value.parse() {
88            Ok(number) => Ok(Value::Integer(number)),
89            Err(_) => Err(Error {
90                cause: EvalError::InvalidVariableValue(value.to_string()),
91                location: location.clone(),
92            }),
93        },
94        Err(e) => Err(Error {
95            cause: EvalError::GetVariableError(e),
96            location: location.clone(),
97        }),
98    }
99}
100
101/// Evaluates a term into a value.
102pub fn into_value<E: Env>(
103    term: Term,
104    env: &E,
105) -> Result<Value, Error<E::GetVariableError, E::AssignVariableError>> {
106    match term {
107        Term::Value(value) => Ok(value),
108        Term::Variable { name, location } => expand_variable(name, &location, env),
109    }
110}
111
112/// Tests if a term is a variable.
113///
114/// If the term is a value, returns an `AssignmentToValue` error with the given
115/// location.
116fn require_variable<'a, E1, E2>(
117    term: Term<'a>,
118    op_location: &Range<usize>,
119) -> Result<(&'a str, Range<usize>), Error<E1, E2>> {
120    match term {
121        Term::Variable { name, location } => Ok((name, location)),
122        Term::Value(_) => Err(Error {
123            cause: EvalError::AssignmentToValue,
124            location: op_location.clone(),
125        }),
126    }
127}
128
129/// Extracts a successful computation result or returns an overflow error.
130fn unwrap_or_overflow<T, E1, E2>(
131    checked_computation: Option<T>,
132    location: &Range<usize>,
133) -> Result<T, Error<E1, E2>> {
134    checked_computation.ok_or_else(|| Error {
135        cause: EvalError::Overflow,
136        location: location.clone(),
137    })
138}
139
140/// Assigns a value to a variable and returns the value.
141fn assign<E: Env>(
142    name: &str,
143    value: Value,
144    location: Range<usize>,
145    env: &mut E,
146) -> Result<Value, Error<E::GetVariableError, E::AssignVariableError>> {
147    match env.assign_variable(name, value.to_string(), location.clone()) {
148        Ok(()) => Ok(value),
149        Err(e) => Err(Error {
150            cause: EvalError::AssignVariableError(e),
151            location,
152        }),
153    }
154}
155
156/// Applies a prefix operator to a term.
157fn apply_prefix<E: Env>(
158    term: Term,
159    operator: PrefixOperator,
160    op_location: &Range<usize>,
161    env: &mut E,
162) -> Result<Value, Error<E::GetVariableError, E::AssignVariableError>> {
163    match operator {
164        PrefixOperator::Increment => {
165            let (name, location) = require_variable(term, op_location)?;
166            match expand_variable(name, &location, env)? {
167                Value::Integer(value) => {
168                    let new_value =
169                        Value::Integer(unwrap_or_overflow(value.checked_add(1), op_location)?);
170                    assign(name, new_value, location, env)
171                }
172            }
173        }
174        PrefixOperator::Decrement => {
175            let (name, location) = require_variable(term, op_location)?;
176            match expand_variable(name, &location, env)? {
177                Value::Integer(value) => {
178                    let new_value =
179                        Value::Integer(unwrap_or_overflow(value.checked_sub(1), op_location)?);
180                    assign(name, new_value, location, env)
181                }
182            }
183        }
184        PrefixOperator::NumericCoercion => into_value(term, env),
185        PrefixOperator::NumericNegation => match into_value(term, env)? {
186            Value::Integer(value) => match value.checked_neg() {
187                Some(result) => Ok(Value::Integer(result)),
188                None => Err(Error {
189                    cause: EvalError::Overflow,
190                    location: op_location.clone(),
191                }),
192            },
193        },
194        PrefixOperator::LogicalNegation => match into_value(term, env)? {
195            Value::Integer(value) => Ok(Value::Integer((value == 0) as _)),
196        },
197        PrefixOperator::BitwiseNegation => match into_value(term, env)? {
198            Value::Integer(value) => Ok(Value::Integer(!value)),
199        },
200    }
201}
202
203/// Applies a postfix operator to a term.
204fn apply_postfix<E: Env>(
205    term: Term,
206    operator: PostfixOperator,
207    op_location: &Range<usize>,
208    env: &mut E,
209) -> Result<Value, Error<E::GetVariableError, E::AssignVariableError>> {
210    let (name, location) = require_variable(term, op_location)?;
211    match expand_variable(name, &location, env)? {
212        old_value @ Value::Integer(value) => {
213            let result = match operator {
214                PostfixOperator::Increment => value.checked_add(1),
215                PostfixOperator::Decrement => value.checked_sub(1),
216            };
217            let new_value = Value::Integer(unwrap_or_overflow(result, op_location)?);
218            assign(name, new_value, location, env)?;
219            Ok(old_value)
220        }
221    }
222}
223
224/// Computes the result value of a binary operator.
225///
226/// If `operator` is a compound assignment operator, this function only computes
227/// the result value without performing assignment.
228fn binary_result<E1, E2>(
229    lhs: Value,
230    rhs: Value,
231    operator: BinaryOperator,
232    op_location: &Range<usize>,
233) -> Result<Value, Error<E1, E2>> {
234    fn require_non_negative<E1, E2>(v: i64, location: &Range<usize>) -> Result<u32, Error<E1, E2>> {
235        v.try_into().map_err(|_| Error {
236            cause: if v < 0 {
237                EvalError::ReverseShifting
238            } else {
239                EvalError::Overflow
240            },
241            location: location.clone(),
242        })
243    }
244    fn require_non_zero<E1, E2>(v: i64, location: &Range<usize>) -> Result<(), Error<E1, E2>> {
245        if v != 0 {
246            Ok(())
247        } else {
248            Err(Error {
249                cause: EvalError::DivisionByZero,
250                location: location.clone(),
251            })
252        }
253    }
254
255    let Value::Integer(lhs) = lhs;
256    let Value::Integer(rhs) = rhs;
257    use BinaryOperator::*;
258    let result = match operator {
259        LogicalOr => Some((lhs != 0 || rhs != 0) as _),
260        LogicalAnd => Some((lhs != 0 && rhs != 0) as _),
261        BitwiseOr | BitwiseOrAssign => Some(lhs | rhs),
262        BitwiseXor | BitwiseXorAssign => Some(lhs ^ rhs),
263        BitwiseAnd | BitwiseAndAssign => Some(lhs & rhs),
264        EqualTo => Some((lhs == rhs) as _),
265        NotEqualTo => Some((lhs != rhs) as _),
266        LessThan => Some((lhs < rhs) as _),
267        GreaterThan => Some((lhs > rhs) as _),
268        LessThanOrEqualTo => Some((lhs <= rhs) as _),
269        GreaterThanOrEqualTo => Some((lhs >= rhs) as _),
270        ShiftLeft | ShiftLeftAssign => {
271            if lhs < 0 {
272                return Err(Error {
273                    cause: EvalError::LeftShiftingNegative,
274                    location: op_location.clone(),
275                });
276            }
277            let rhs = require_non_negative(rhs, op_location)?;
278            lhs.checked_shl(rhs)
279                .filter(|&result| result >= 0 && result >> rhs == lhs)
280        }
281        ShiftRight | ShiftRightAssign => {
282            let rhs = require_non_negative(rhs, op_location)?;
283            lhs.checked_shr(rhs)
284        }
285        Add | AddAssign => lhs.checked_add(rhs),
286        Subtract | SubtractAssign => lhs.checked_sub(rhs),
287        Multiply | MultiplyAssign => lhs.checked_mul(rhs),
288        Divide | DivideAssign => {
289            require_non_zero(rhs, op_location)?;
290            lhs.checked_div(rhs)
291        }
292        Remainder | RemainderAssign => {
293            require_non_zero(rhs, op_location)?;
294            lhs.checked_rem(rhs)
295        }
296        Assign => Some(rhs),
297    };
298    let result = unwrap_or_overflow(result, op_location)?;
299    Ok(Value::Integer(result))
300}
301
302/// Applies a binary operator.
303fn apply_binary<'a, E: Env>(
304    lhs: Term<'a>,
305    rhs: Term<'a>,
306    operator: BinaryOperator,
307    op_location: &Range<usize>,
308    env: &mut E,
309) -> Result<Value, Error<E::GetVariableError, E::AssignVariableError>> {
310    use BinaryOperator::*;
311    match operator {
312        LogicalOr | LogicalAnd | BitwiseOr | BitwiseXor | BitwiseAnd | EqualTo | NotEqualTo
313        | LessThan | GreaterThan | LessThanOrEqualTo | GreaterThanOrEqualTo | ShiftLeft
314        | ShiftRight | Add | Subtract | Multiply | Divide | Remainder => {
315            let lhs = into_value(lhs, env)?;
316            let rhs = into_value(rhs, env)?;
317            binary_result(lhs, rhs, operator, op_location)
318        }
319        Assign => {
320            let (name, location) = require_variable(lhs, op_location)?;
321            let value = into_value(rhs, env)?;
322            assign(name, value, location, env)
323        }
324        BitwiseOrAssign | BitwiseXorAssign | BitwiseAndAssign | ShiftLeftAssign
325        | ShiftRightAssign | AddAssign | SubtractAssign | MultiplyAssign | DivideAssign
326        | RemainderAssign => {
327            let (name, location) = require_variable(lhs, op_location)?;
328            let lhs = expand_variable(name, &location, env)?;
329            let rhs = into_value(rhs, env)?;
330            let result = binary_result(lhs, rhs, operator, op_location)?;
331            assign(name, result, location, env)
332        }
333    }
334}
335
336/// Evaluates an expression.
337///
338/// The given `ast` must not be empty, or this function will **panic**.
339pub fn eval<'a, E: Env>(
340    ast: &[Ast<'a>],
341    env: &mut E,
342) -> Result<Term<'a>, Error<E::GetVariableError, E::AssignVariableError>> {
343    let (root, children) = ast
344        .split_last()
345        .expect("the expression should not be empty");
346    match root {
347        Ast::Term(term) => Ok(term.clone()),
348
349        Ast::Prefix { operator, location } => {
350            let term = eval(children, env)?;
351            apply_prefix(term, *operator, location, env).map(Term::Value)
352        }
353
354        Ast::Postfix { operator, location } => {
355            let term = eval(children, env)?;
356            apply_postfix(term, *operator, location, env).map(Term::Value)
357        }
358
359        Ast::Binary {
360            operator: BinaryOperator::LogicalOr,
361            rhs_len,
362            location,
363        } => {
364            let (lhs_ast, rhs_ast) = children.split_at(children.len() - rhs_len);
365            let lhs = into_value(eval(lhs_ast, env)?, env)?;
366            if lhs != Value::Integer(0) {
367                return Ok(Term::Value(Value::Integer(1)));
368            }
369            let rhs = into_value(eval(rhs_ast, env)?, env)?;
370            binary_result(lhs, rhs, BinaryOperator::LogicalOr, location).map(Term::Value)
371        }
372
373        Ast::Binary {
374            operator: BinaryOperator::LogicalAnd,
375            rhs_len,
376            location,
377        } => {
378            let (lhs_ast, rhs_ast) = children.split_at(children.len() - rhs_len);
379            let lhs = into_value(eval(lhs_ast, env)?, env)?;
380            if lhs == Value::Integer(0) {
381                return Ok(Term::Value(Value::Integer(0)));
382            }
383            let rhs = into_value(eval(rhs_ast, env)?, env)?;
384            binary_result(lhs, rhs, BinaryOperator::LogicalAnd, location).map(Term::Value)
385        }
386
387        Ast::Binary {
388            operator,
389            rhs_len,
390            location,
391        } => {
392            let (lhs_ast, rhs_ast) = children.split_at(children.len() - rhs_len);
393            let lhs = eval(lhs_ast, env)?;
394            let rhs = eval(rhs_ast, env)?;
395            apply_binary(lhs, rhs, *operator, location, env).map(Term::Value)
396        }
397
398        Ast::Conditional { then_len, else_len } => {
399            let (children_2, else_ast) = children.split_at(children.len() - else_len);
400            let (condition_ast, then_ast) = children_2.split_at(children_2.len() - then_len);
401            let condition = into_value(eval(condition_ast, env)?, env)?;
402            let result_ast = if condition != Value::Integer(0) {
403                then_ast
404            } else {
405                else_ast
406            };
407            eval(result_ast, env)
408        }
409    }
410}
411
412#[cfg(test)]
413mod tests {
414    use super::*;
415    use std::collections::HashMap;
416    use std::convert::Infallible;
417
418    #[test]
419    fn expand_variable_non_existing() {
420        let env = &mut HashMap::new();
421        assert_eq!(expand_variable("a", &(10..11), env), Ok(Value::Integer(0)));
422        assert_eq!(expand_variable("b", &(11..12), env), Ok(Value::Integer(0)));
423    }
424
425    #[test]
426    fn expand_variable_valid() {
427        let env = &mut HashMap::new();
428        env.insert("a".to_string(), "42".to_string());
429        env.insert("b".to_string(), "-123".to_string());
430        assert_eq!(expand_variable("a", &(10..11), env), Ok(Value::Integer(42)));
431        assert_eq!(
432            expand_variable("b", &(11..12), env),
433            Ok(Value::Integer(-123))
434        );
435    }
436
437    #[test]
438    fn expand_variable_invalid() {
439        let env = &mut HashMap::new();
440        env.insert("a".to_string(), "*".to_string());
441        assert_eq!(
442            expand_variable("a", &(10..11), env),
443            Err(Error {
444                cause: EvalError::InvalidVariableValue("*".to_string()),
445                location: 10..11,
446            })
447        );
448    }
449
450    #[test]
451    fn apply_prefix_increment() {
452        let env = &mut HashMap::new();
453
454        assert_eq!(
455            apply_prefix(
456                Term::Variable {
457                    name: "i",
458                    location: 6..7
459                },
460                PrefixOperator::Increment,
461                &(3..5),
462                env
463            ),
464            Ok(Value::Integer(1))
465        );
466        assert_eq!(env["i"], "1");
467
468        assert_eq!(
469            apply_prefix(
470                Term::Variable {
471                    name: "i",
472                    location: 6..7
473                },
474                PrefixOperator::Increment,
475                &(3..5),
476                env
477            ),
478            Ok(Value::Integer(2))
479        );
480        assert_eq!(env["i"], "2");
481    }
482
483    #[test]
484    fn apply_prefix_increment_overflow() {
485        let env = &mut HashMap::new();
486        env.insert("i".to_string(), "9223372036854775807".to_string());
487        assert_eq!(
488            apply_prefix(
489                Term::Variable {
490                    name: "i",
491                    location: 6..7
492                },
493                PrefixOperator::Increment,
494                &(3..5),
495                env
496            ),
497            Err(Error {
498                cause: EvalError::Overflow,
499                location: 3..5,
500            })
501        );
502    }
503
504    #[test]
505    fn apply_prefix_increment_not_variable() {
506        let env = &mut HashMap::new();
507        assert_eq!(
508            apply_prefix(
509                Term::Value(Value::Integer(3)),
510                PrefixOperator::Increment,
511                &(3..5),
512                env
513            ),
514            Err(Error {
515                cause: EvalError::AssignmentToValue,
516                location: 3..5,
517            })
518        );
519    }
520
521    #[test]
522    fn apply_prefix_decrement() {
523        let env = &mut HashMap::new();
524
525        assert_eq!(
526            apply_prefix(
527                Term::Variable {
528                    name: "i",
529                    location: 6..7
530                },
531                PrefixOperator::Decrement,
532                &(3..5),
533                env
534            ),
535            Ok(Value::Integer(-1))
536        );
537        assert_eq!(env["i"], "-1");
538
539        assert_eq!(
540            apply_prefix(
541                Term::Variable {
542                    name: "i",
543                    location: 6..7
544                },
545                PrefixOperator::Decrement,
546                &(3..5),
547                env
548            ),
549            Ok(Value::Integer(-2))
550        );
551        assert_eq!(env["i"], "-2");
552    }
553
554    #[test]
555    fn apply_prefix_decrement_overflow() {
556        let env = &mut HashMap::new();
557        env.insert("i".to_string(), "-9223372036854775808".to_string());
558        assert_eq!(
559            apply_prefix(
560                Term::Variable {
561                    name: "i",
562                    location: 6..7
563                },
564                PrefixOperator::Decrement,
565                &(3..5),
566                env
567            ),
568            Err(Error {
569                cause: EvalError::Overflow,
570                location: 3..5,
571            })
572        );
573    }
574
575    #[test]
576    fn apply_prefix_decrement_not_variable() {
577        let env = &mut HashMap::new();
578        assert_eq!(
579            apply_prefix(
580                Term::Value(Value::Integer(3)),
581                PrefixOperator::Decrement,
582                &(3..5),
583                env
584            ),
585            Err(Error {
586                cause: EvalError::AssignmentToValue,
587                location: 3..5,
588            })
589        );
590    }
591
592    #[test]
593    fn apply_prefix_numeric_coercion() {
594        let env = &mut HashMap::new();
595        env.insert("a".to_string(), "12".to_string());
596        assert_eq!(
597            apply_prefix(
598                Term::Value(Value::Integer(7)),
599                PrefixOperator::NumericCoercion,
600                &(3..4),
601                env
602            ),
603            Ok(Value::Integer(7))
604        );
605        assert_eq!(
606            apply_prefix(
607                Term::Variable {
608                    name: "a",
609                    location: 5..7,
610                },
611                PrefixOperator::NumericCoercion,
612                &(3..4),
613                env
614            ),
615            Ok(Value::Integer(12))
616        );
617    }
618
619    #[test]
620    fn apply_prefix_numeric_negation() {
621        let env = &mut HashMap::new();
622        assert_eq!(
623            apply_prefix(
624                Term::Value(Value::Integer(7)),
625                PrefixOperator::NumericNegation,
626                &(3..4),
627                env
628            ),
629            Ok(Value::Integer(-7))
630        );
631        assert_eq!(
632            apply_prefix(
633                Term::Value(Value::Integer(-10)),
634                PrefixOperator::NumericNegation,
635                &(3..4),
636                env
637            ),
638            Ok(Value::Integer(10))
639        );
640    }
641
642    #[test]
643    fn apply_prefix_numeric_negation_overflow() {
644        let env = &mut HashMap::new();
645        assert_eq!(
646            apply_prefix(
647                Term::Value(Value::Integer(i64::MIN)),
648                PrefixOperator::NumericNegation,
649                &(3..4),
650                env
651            ),
652            Err(Error {
653                cause: EvalError::Overflow,
654                location: 3..4,
655            })
656        );
657    }
658
659    #[test]
660    fn apply_prefix_logical_negation() {
661        let env = &mut HashMap::new();
662        assert_eq!(
663            apply_prefix(
664                Term::Value(Value::Integer(0)),
665                PrefixOperator::LogicalNegation,
666                &(3..4),
667                env
668            ),
669            Ok(Value::Integer(1))
670        );
671
672        for i in [-1, 1, 2, 100, i64::MAX, i64::MIN] {
673            assert_eq!(
674                apply_prefix(
675                    Term::Value(Value::Integer(i)),
676                    PrefixOperator::LogicalNegation,
677                    &(3..4),
678                    env
679                ),
680                Ok(Value::Integer(0)),
681                "i={i:?}"
682            );
683        }
684    }
685
686    #[test]
687    fn apply_prefix_bitwise_negation() {
688        let env = &mut HashMap::new();
689        assert_eq!(
690            apply_prefix(
691                Term::Value(Value::Integer(0)),
692                PrefixOperator::BitwiseNegation,
693                &(3..4),
694                env
695            ),
696            Ok(Value::Integer(!0))
697        );
698        assert_eq!(
699            apply_prefix(
700                Term::Value(Value::Integer(-10000)),
701                PrefixOperator::BitwiseNegation,
702                &(3..4),
703                env
704            ),
705            Ok(Value::Integer(!-10000))
706        );
707    }
708
709    #[test]
710    fn apply_postfix_increment() {
711        let env = &mut HashMap::new();
712
713        assert_eq!(
714            apply_postfix(
715                Term::Variable {
716                    name: "i",
717                    location: 0..1,
718                },
719                PostfixOperator::Increment,
720                &(3..5),
721                env
722            ),
723            Ok(Value::Integer(0))
724        );
725        assert_eq!(env["i"], "1");
726
727        assert_eq!(
728            apply_postfix(
729                Term::Variable {
730                    name: "i",
731                    location: 0..1,
732                },
733                PostfixOperator::Increment,
734                &(3..5),
735                env
736            ),
737            Ok(Value::Integer(1))
738        );
739        assert_eq!(env["i"], "2");
740    }
741
742    #[test]
743    fn apply_postfix_increment_overflow() {
744        let env = &mut HashMap::new();
745        env.insert("i".to_string(), "9223372036854775807".to_string());
746        assert_eq!(
747            apply_postfix(
748                Term::Variable {
749                    name: "i",
750                    location: 0..1,
751                },
752                PostfixOperator::Increment,
753                &(3..5),
754                env
755            ),
756            Err(Error {
757                cause: EvalError::Overflow,
758                location: 3..5,
759            })
760        );
761    }
762
763    #[test]
764    fn apply_postfix_increment_not_variable() {
765        let env = &mut HashMap::new();
766        assert_eq!(
767            apply_postfix(
768                Term::Value(Value::Integer(13)),
769                PostfixOperator::Increment,
770                &(3..5),
771                env
772            ),
773            Err(Error {
774                cause: EvalError::AssignmentToValue,
775                location: 3..5,
776            })
777        );
778    }
779
780    #[test]
781    fn apply_postfix_decrement() {
782        let env = &mut HashMap::new();
783
784        assert_eq!(
785            apply_postfix(
786                Term::Variable {
787                    name: "i",
788                    location: 0..1,
789                },
790                PostfixOperator::Decrement,
791                &(3..5),
792                env
793            ),
794            Ok(Value::Integer(0))
795        );
796        assert_eq!(env["i"], "-1");
797
798        assert_eq!(
799            apply_postfix(
800                Term::Variable {
801                    name: "i",
802                    location: 0..1,
803                },
804                PostfixOperator::Decrement,
805                &(3..5),
806                env
807            ),
808            Ok(Value::Integer(-1))
809        );
810        assert_eq!(env["i"], "-2");
811    }
812
813    #[test]
814    fn apply_postfix_decrement_overflow() {
815        let env = &mut HashMap::new();
816        env.insert("i".to_string(), "-9223372036854775808".to_string());
817        assert_eq!(
818            apply_postfix(
819                Term::Variable {
820                    name: "i",
821                    location: 0..1,
822                },
823                PostfixOperator::Decrement,
824                &(3..5),
825                env
826            ),
827            Err(Error {
828                cause: EvalError::Overflow,
829                location: 3..5,
830            })
831        );
832    }
833
834    #[test]
835    fn apply_postfix_decrement_not_variable() {
836        let env = &mut HashMap::new();
837        assert_eq!(
838            apply_postfix(
839                Term::Value(Value::Integer(13)),
840                PostfixOperator::Decrement,
841                &(3..5),
842                env
843            ),
844            Err(Error {
845                cause: EvalError::AssignmentToValue,
846                location: 3..5,
847            })
848        );
849    }
850
851    #[test]
852    fn binary_result_logical_or() {
853        let zero = Value::Integer(0);
854        let one = Value::Integer(1);
855        let two = Value::Integer(2);
856        let operator = BinaryOperator::LogicalOr;
857        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
858        assert_eq!(result, Ok(Value::Integer(0)));
859        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
860        assert_eq!(result, Ok(Value::Integer(1)));
861        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
862        assert_eq!(result, Ok(Value::Integer(1)));
863        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
864        assert_eq!(result, Ok(Value::Integer(1)));
865    }
866
867    #[test]
868    fn binary_result_logical_and() {
869        let zero = Value::Integer(0);
870        let one = Value::Integer(1);
871        let two = Value::Integer(2);
872        let operator = BinaryOperator::LogicalAnd;
873        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
874        assert_eq!(result, Ok(Value::Integer(0)));
875        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
876        assert_eq!(result, Ok(Value::Integer(0)));
877        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
878        assert_eq!(result, Ok(Value::Integer(1)));
879        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
880        assert_eq!(result, Ok(Value::Integer(0)));
881    }
882
883    #[test]
884    fn binary_result_bitwise_or() {
885        let zero = Value::Integer(0);
886        let three = Value::Integer(3);
887        let six = Value::Integer(6);
888        for operator in [BinaryOperator::BitwiseOr, BinaryOperator::BitwiseOrAssign] {
889            let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..4));
890            assert_eq!(result, Ok(Value::Integer(0)));
891            let result = binary_result::<Infallible, Infallible>(three, zero, operator, &(3..4));
892            assert_eq!(result, Ok(Value::Integer(3)));
893            let result = binary_result::<Infallible, Infallible>(three, six, operator, &(3..4));
894            assert_eq!(result, Ok(Value::Integer(7)));
895            let result = binary_result::<Infallible, Infallible>(zero, six, operator, &(3..4));
896            assert_eq!(result, Ok(Value::Integer(6)));
897        }
898    }
899
900    #[test]
901    fn binary_result_bitwise_xor() {
902        let zero = Value::Integer(0);
903        let three = Value::Integer(3);
904        let six = Value::Integer(6);
905        for operator in [BinaryOperator::BitwiseXor, BinaryOperator::BitwiseXorAssign] {
906            let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..4));
907            assert_eq!(result, Ok(Value::Integer(0)));
908            let result = binary_result::<Infallible, Infallible>(three, zero, operator, &(3..4));
909            assert_eq!(result, Ok(Value::Integer(3)));
910            let result = binary_result::<Infallible, Infallible>(three, six, operator, &(3..4));
911            assert_eq!(result, Ok(Value::Integer(5)));
912            let result = binary_result::<Infallible, Infallible>(zero, six, operator, &(3..4));
913            assert_eq!(result, Ok(Value::Integer(6)));
914        }
915    }
916
917    #[test]
918    fn binary_result_bitwise_and() {
919        let zero = Value::Integer(0);
920        let three = Value::Integer(3);
921        let six = Value::Integer(6);
922        for operator in [BinaryOperator::BitwiseAnd, BinaryOperator::BitwiseAndAssign] {
923            let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..4));
924            assert_eq!(result, Ok(Value::Integer(0)));
925            let result = binary_result::<Infallible, Infallible>(three, zero, operator, &(3..4));
926            assert_eq!(result, Ok(Value::Integer(0)));
927            let result = binary_result::<Infallible, Infallible>(three, six, operator, &(3..4));
928            assert_eq!(result, Ok(Value::Integer(2)));
929            let result = binary_result::<Infallible, Infallible>(zero, six, operator, &(3..4));
930            assert_eq!(result, Ok(Value::Integer(0)));
931        }
932    }
933
934    #[test]
935    fn binary_result_equal_to() {
936        let zero = Value::Integer(0);
937        let one = Value::Integer(1);
938        let two = Value::Integer(2);
939        let operator = BinaryOperator::EqualTo;
940        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
941        assert_eq!(result, Ok(Value::Integer(1)));
942        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
943        assert_eq!(result, Ok(Value::Integer(1)));
944        let result = binary_result::<Infallible, Infallible>(two, two, operator, &(3..5));
945        assert_eq!(result, Ok(Value::Integer(1)));
946        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
947        assert_eq!(result, Ok(Value::Integer(0)));
948        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
949        assert_eq!(result, Ok(Value::Integer(0)));
950        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
951        assert_eq!(result, Ok(Value::Integer(0)));
952    }
953
954    #[test]
955    fn binary_result_not_equal_to() {
956        let zero = Value::Integer(0);
957        let one = Value::Integer(1);
958        let two = Value::Integer(2);
959        let operator = BinaryOperator::NotEqualTo;
960        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
961        assert_eq!(result, Ok(Value::Integer(0)));
962        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
963        assert_eq!(result, Ok(Value::Integer(0)));
964        let result = binary_result::<Infallible, Infallible>(two, two, operator, &(3..5));
965        assert_eq!(result, Ok(Value::Integer(0)));
966        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
967        assert_eq!(result, Ok(Value::Integer(1)));
968        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
969        assert_eq!(result, Ok(Value::Integer(1)));
970        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
971        assert_eq!(result, Ok(Value::Integer(1)));
972    }
973
974    #[test]
975    fn binary_result_less_than() {
976        let zero = Value::Integer(0);
977        let one = Value::Integer(1);
978        let two = Value::Integer(2);
979        let operator = BinaryOperator::LessThan;
980        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
981        assert_eq!(result, Ok(Value::Integer(0)));
982        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
983        assert_eq!(result, Ok(Value::Integer(0)));
984        let result = binary_result::<Infallible, Infallible>(two, two, operator, &(3..5));
985        assert_eq!(result, Ok(Value::Integer(0)));
986        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
987        assert_eq!(result, Ok(Value::Integer(0)));
988        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
989        assert_eq!(result, Ok(Value::Integer(1)));
990        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
991        assert_eq!(result, Ok(Value::Integer(1)));
992    }
993
994    #[test]
995    fn binary_result_greater_than() {
996        let zero = Value::Integer(0);
997        let one = Value::Integer(1);
998        let two = Value::Integer(2);
999        let operator = BinaryOperator::GreaterThan;
1000        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
1001        assert_eq!(result, Ok(Value::Integer(0)));
1002        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
1003        assert_eq!(result, Ok(Value::Integer(0)));
1004        let result = binary_result::<Infallible, Infallible>(two, one, operator, &(3..5));
1005        assert_eq!(result, Ok(Value::Integer(1)));
1006        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
1007        assert_eq!(result, Ok(Value::Integer(1)));
1008        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
1009        assert_eq!(result, Ok(Value::Integer(0)));
1010        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
1011        assert_eq!(result, Ok(Value::Integer(0)));
1012    }
1013
1014    #[test]
1015    fn binary_result_less_than_or_equal_to() {
1016        let zero = Value::Integer(0);
1017        let one = Value::Integer(1);
1018        let two = Value::Integer(2);
1019        let operator = BinaryOperator::LessThanOrEqualTo;
1020        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
1021        assert_eq!(result, Ok(Value::Integer(1)));
1022        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
1023        assert_eq!(result, Ok(Value::Integer(1)));
1024        let result = binary_result::<Infallible, Infallible>(two, one, operator, &(3..5));
1025        assert_eq!(result, Ok(Value::Integer(0)));
1026        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
1027        assert_eq!(result, Ok(Value::Integer(0)));
1028        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
1029        assert_eq!(result, Ok(Value::Integer(1)));
1030        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
1031        assert_eq!(result, Ok(Value::Integer(1)));
1032    }
1033
1034    #[test]
1035    fn binary_result_greater_than_or_equal_to() {
1036        let zero = Value::Integer(0);
1037        let one = Value::Integer(1);
1038        let two = Value::Integer(2);
1039        let operator = BinaryOperator::GreaterThanOrEqualTo;
1040        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
1041        assert_eq!(result, Ok(Value::Integer(1)));
1042        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
1043        assert_eq!(result, Ok(Value::Integer(1)));
1044        let result = binary_result::<Infallible, Infallible>(two, one, operator, &(3..5));
1045        assert_eq!(result, Ok(Value::Integer(1)));
1046        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
1047        assert_eq!(result, Ok(Value::Integer(1)));
1048        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
1049        assert_eq!(result, Ok(Value::Integer(0)));
1050        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
1051        assert_eq!(result, Ok(Value::Integer(0)));
1052    }
1053
1054    #[test]
1055    fn binary_result_shift_left() {
1056        let lhs = Value::Integer(0x94E239);
1057        let rhs = Value::Integer(7);
1058        for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1059            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1060            assert_eq!(result, Ok(Value::Integer(0x94E239 << 7)));
1061        }
1062    }
1063
1064    #[test]
1065    fn binary_result_shift_left_negative_lhs() {
1066        let lhs = Value::Integer(-1);
1067        let rhs = Value::Integer(0);
1068        for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1069            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1070            assert_eq!(
1071                result,
1072                Err(Error {
1073                    cause: EvalError::LeftShiftingNegative,
1074                    location: 3..4,
1075                })
1076            );
1077        }
1078    }
1079
1080    #[test]
1081    fn binary_result_shift_left_negative_rhs() {
1082        let lhs = Value::Integer(0);
1083        let rhs = Value::Integer(-1);
1084        for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1085            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1086            assert_eq!(
1087                result,
1088                Err(Error {
1089                    cause: EvalError::ReverseShifting,
1090                    location: 3..4,
1091                })
1092            );
1093        }
1094    }
1095
1096    #[test]
1097    fn binary_result_shift_left_too_large_rhs() {
1098        let lhs = Value::Integer(0);
1099        for rhs in [i64::BITS as i64, i64::MAX] {
1100            let rhs = Value::Integer(rhs);
1101            for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1102                let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1103                assert_eq!(
1104                    result,
1105                    Err(Error {
1106                        cause: EvalError::Overflow,
1107                        location: 3..4,
1108                    })
1109                );
1110            }
1111        }
1112    }
1113
1114    #[test]
1115    fn binary_result_shift_left_overflow_to_sign_bit() {
1116        let lhs = Value::Integer(0x4000_0000_0000_0000);
1117        let rhs = Value::Integer(1);
1118        for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1119            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1120            assert_eq!(
1121                result,
1122                Err(Error {
1123                    cause: EvalError::Overflow,
1124                    location: 3..4,
1125                })
1126            );
1127        }
1128    }
1129
1130    #[test]
1131    fn binary_result_shift_left_overflow_beyond_sign_bit() {
1132        let lhs = Value::Integer(0x4000_0000_0000_0000);
1133        let rhs = Value::Integer(2);
1134        for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1135            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1136            assert_eq!(
1137                result,
1138                Err(Error {
1139                    cause: EvalError::Overflow,
1140                    location: 3..4,
1141                })
1142            );
1143        }
1144    }
1145
1146    #[test]
1147    fn binary_result_shift_right() {
1148        let lhs = Value::Integer(0x94E239);
1149        let rhs = Value::Integer(7);
1150        for operator in [BinaryOperator::ShiftRight, BinaryOperator::ShiftRightAssign] {
1151            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1152            assert_eq!(result, Ok(Value::Integer(0x94E239 >> 7)));
1153        }
1154    }
1155
1156    #[test]
1157    fn binary_result_shift_right_negative_rhs() {
1158        let lhs = Value::Integer(0);
1159        let rhs = Value::Integer(-1);
1160        for operator in [BinaryOperator::ShiftRight, BinaryOperator::ShiftRightAssign] {
1161            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1162            assert_eq!(
1163                result,
1164                Err(Error {
1165                    cause: EvalError::ReverseShifting,
1166                    location: 3..4,
1167                })
1168            );
1169        }
1170    }
1171
1172    #[test]
1173    fn binary_result_shift_right_too_large_rhs() {
1174        let lhs = Value::Integer(0);
1175        let rhs = Value::Integer(i64::BITS as _);
1176        for operator in [BinaryOperator::ShiftRight, BinaryOperator::ShiftRightAssign] {
1177            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1178            assert_eq!(
1179                result,
1180                Err(Error {
1181                    cause: EvalError::Overflow,
1182                    location: 3..4,
1183                })
1184            );
1185        }
1186    }
1187
1188    #[test]
1189    fn binary_result_add() {
1190        let lhs = Value::Integer(15);
1191        let rhs = Value::Integer(27);
1192        for operator in [BinaryOperator::Add, BinaryOperator::AddAssign] {
1193            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1194            assert_eq!(result, Ok(Value::Integer(42)));
1195        }
1196    }
1197
1198    #[test]
1199    fn binary_result_add_overflow() {
1200        let lhs = Value::Integer(i64::MIN);
1201        let rhs = Value::Integer(-1);
1202        for operator in [BinaryOperator::Add, BinaryOperator::AddAssign] {
1203            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1204            assert_eq!(
1205                result,
1206                Err(Error {
1207                    cause: EvalError::Overflow,
1208                    location: 3..4,
1209                })
1210            );
1211        }
1212    }
1213
1214    #[test]
1215    fn binary_result_subtract() {
1216        let lhs = Value::Integer(15);
1217        let rhs = Value::Integer(27);
1218        for operator in [BinaryOperator::Subtract, BinaryOperator::SubtractAssign] {
1219            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1220            assert_eq!(result, Ok(Value::Integer(-12)));
1221        }
1222    }
1223
1224    #[test]
1225    fn binary_result_subtract_overflow() {
1226        let lhs = Value::Integer(i64::MAX);
1227        let rhs = Value::Integer(-1);
1228        for operator in [BinaryOperator::Subtract, BinaryOperator::SubtractAssign] {
1229            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1230            assert_eq!(
1231                result,
1232                Err(Error {
1233                    cause: EvalError::Overflow,
1234                    location: 3..4,
1235                })
1236            );
1237        }
1238    }
1239
1240    #[test]
1241    fn binary_result_multiply() {
1242        let lhs = Value::Integer(15);
1243        let rhs = Value::Integer(27);
1244        for operator in [BinaryOperator::Multiply, BinaryOperator::MultiplyAssign] {
1245            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1246            assert_eq!(result, Ok(Value::Integer(405)));
1247        }
1248    }
1249
1250    #[test]
1251    fn binary_result_multiply_overflow() {
1252        let lhs = Value::Integer(0x4000_0000_0000_0000);
1253        let rhs = Value::Integer(2);
1254        for operator in [BinaryOperator::Multiply, BinaryOperator::MultiplyAssign] {
1255            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1256            assert_eq!(
1257                result,
1258                Err(Error {
1259                    cause: EvalError::Overflow,
1260                    location: 3..4,
1261                })
1262            );
1263        }
1264    }
1265
1266    #[test]
1267    fn binary_result_divide() {
1268        let lhs = Value::Integer(268);
1269        let rhs = Value::Integer(17);
1270        for operator in [BinaryOperator::Divide, BinaryOperator::DivideAssign] {
1271            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1272            assert_eq!(result, Ok(Value::Integer(15)));
1273        }
1274    }
1275
1276    #[test]
1277    fn binary_result_divide_overflow() {
1278        let lhs = Value::Integer(i64::MIN);
1279        let rhs = Value::Integer(-1);
1280        for operator in [BinaryOperator::Divide, BinaryOperator::DivideAssign] {
1281            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1282            assert_eq!(
1283                result,
1284                Err(Error {
1285                    cause: EvalError::Overflow,
1286                    location: 3..4,
1287                })
1288            );
1289        }
1290    }
1291
1292    #[test]
1293    fn binary_result_divide_by_zero() {
1294        let lhs = Value::Integer(1);
1295        let rhs = Value::Integer(0);
1296        for operator in [BinaryOperator::Divide, BinaryOperator::DivideAssign] {
1297            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1298            assert_eq!(
1299                result,
1300                Err(Error {
1301                    cause: EvalError::DivisionByZero,
1302                    location: 3..4,
1303                })
1304            );
1305        }
1306    }
1307
1308    #[test]
1309    fn binary_result_remainder() {
1310        let lhs = Value::Integer(268);
1311        let rhs = Value::Integer(17);
1312        for operator in [BinaryOperator::Remainder, BinaryOperator::RemainderAssign] {
1313            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1314            assert_eq!(result, Ok(Value::Integer(13)));
1315        }
1316    }
1317
1318    #[test]
1319    fn binary_result_remainder_overflow() {
1320        let lhs = Value::Integer(i64::MIN);
1321        let rhs = Value::Integer(-1);
1322        for operator in [BinaryOperator::Remainder, BinaryOperator::RemainderAssign] {
1323            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1324            assert_eq!(
1325                result,
1326                Err(Error {
1327                    cause: EvalError::Overflow,
1328                    location: 3..4,
1329                })
1330            );
1331        }
1332    }
1333
1334    #[test]
1335    fn binary_result_remainder_by_zero() {
1336        let lhs = Value::Integer(1);
1337        let rhs = Value::Integer(0);
1338        for operator in [BinaryOperator::Remainder, BinaryOperator::RemainderAssign] {
1339            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1340            assert_eq!(
1341                result,
1342                Err(Error {
1343                    cause: EvalError::DivisionByZero,
1344                    location: 3..4,
1345                })
1346            );
1347        }
1348    }
1349
1350    #[test]
1351    fn apply_binary_add() {
1352        let env = &mut HashMap::new();
1353        let lhs = Term::Value(Value::Integer(30));
1354        let rhs = Term::Value(Value::Integer(12));
1355        let operator = BinaryOperator::Add;
1356        let op_location = 4..5;
1357        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1358        assert_eq!(result, Ok(Value::Integer(42)));
1359    }
1360
1361    #[test]
1362    fn apply_binary_add_overflow() {
1363        let env = &mut HashMap::new();
1364        let lhs = Term::Value(Value::Integer(i64::MAX));
1365        let rhs = Term::Value(Value::Integer(1));
1366        let operator = BinaryOperator::Add;
1367        let op_location = 4..5;
1368        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1369        assert_eq!(
1370            result,
1371            Err(Error {
1372                cause: EvalError::Overflow,
1373                location: 4..5,
1374            })
1375        );
1376    }
1377
1378    #[test]
1379    fn apply_binary_subtract() {
1380        let env = &mut HashMap::new();
1381        let lhs = Term::Value(Value::Integer(30));
1382        let rhs = Term::Value(Value::Integer(12));
1383        let operator = BinaryOperator::Subtract;
1384        let op_location = 4..5;
1385        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1386        assert_eq!(result, Ok(Value::Integer(18)));
1387    }
1388
1389    #[test]
1390    fn apply_binary_subtract_overflow() {
1391        let env = &mut HashMap::new();
1392        let lhs = Term::Value(Value::Integer(i64::MIN));
1393        let rhs = Term::Value(Value::Integer(1));
1394        let operator = BinaryOperator::Subtract;
1395        let op_location = 4..5;
1396        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1397        assert_eq!(
1398            result,
1399            Err(Error {
1400                cause: EvalError::Overflow,
1401                location: 4..5,
1402            })
1403        );
1404    }
1405
1406    #[test]
1407    fn apply_binary_assign() {
1408        let env = &mut HashMap::new();
1409        let lhs = Term::Variable {
1410            name: "foo",
1411            location: 1..4,
1412        };
1413        let rhs = Term::Value(Value::Integer(42));
1414        let operator = BinaryOperator::Assign;
1415        let op_location = 4..5;
1416        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1417        assert_eq!(result, Ok(Value::Integer(42)));
1418        assert_eq!(env["foo"], "42");
1419    }
1420
1421    #[test]
1422    fn apply_binary_assign_not_variable() {
1423        let env = &mut HashMap::new();
1424        let lhs = Term::Value(Value::Integer(3));
1425        let rhs = Term::Value(Value::Integer(42));
1426        let operator = BinaryOperator::Assign;
1427        let op_location = 4..5;
1428        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1429        assert_eq!(
1430            result,
1431            Err(Error {
1432                cause: EvalError::AssignmentToValue,
1433                location: 4..5,
1434            })
1435        );
1436    }
1437
1438    #[test]
1439    fn apply_binary_add_assign() {
1440        let env = &mut HashMap::new();
1441        env.insert("a".to_string(), "10".to_string());
1442        let lhs = Term::Variable {
1443            name: "a",
1444            location: 1..2,
1445        };
1446        let rhs = Term::Value(Value::Integer(32));
1447        let operator = BinaryOperator::AddAssign;
1448        let op_location = 4..6;
1449        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1450        assert_eq!(result, Ok(Value::Integer(42)));
1451        assert_eq!(env["a"], "42");
1452    }
1453
1454    #[test]
1455    fn apply_binary_add_assign_not_variable() {
1456        let env = &mut HashMap::new();
1457        let lhs = Term::Value(Value::Integer(3));
1458        let rhs = Term::Value(Value::Integer(42));
1459        let operator = BinaryOperator::AddAssign;
1460        let op_location = 4..6;
1461        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1462        assert_eq!(
1463            result,
1464            Err(Error {
1465                cause: EvalError::AssignmentToValue,
1466                location: 4..6,
1467            })
1468        );
1469    }
1470
1471    #[test]
1472    fn eval_term() {
1473        let env = &mut HashMap::new();
1474
1475        let t = Term::Value(Value::Integer(42));
1476        assert_eq!(eval(&[Ast::Term(t.clone())], env), Ok(t));
1477
1478        let t = Term::Variable {
1479            name: "a",
1480            location: 10..11,
1481        };
1482        assert_eq!(eval(&[Ast::Term(t.clone())], env), Ok(t));
1483    }
1484
1485    #[test]
1486    fn eval_prefix() {
1487        let env = &mut HashMap::new();
1488        let ast = &[
1489            Ast::Term(Term::Value(Value::Integer(15))),
1490            Ast::Prefix {
1491                operator: PrefixOperator::NumericNegation,
1492                location: 2..3,
1493            },
1494        ];
1495        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(-15))));
1496    }
1497
1498    #[test]
1499    fn eval_postfix() {
1500        let env = &mut HashMap::new();
1501        let ast = &[
1502            Ast::Term(Term::Variable {
1503                name: "x",
1504                location: 0..1,
1505            }),
1506            Ast::Postfix {
1507                operator: PostfixOperator::Increment,
1508                location: 1..3,
1509            },
1510        ];
1511        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(0))));
1512    }
1513
1514    #[test]
1515    fn eval_logical_or_short_circuit() {
1516        let env = &mut HashMap::new();
1517        env.insert("a".to_string(), "*".to_string());
1518        let ast = &[
1519            Ast::Term(Term::Value(Value::Integer(-1))),
1520            Ast::Term(Term::Variable {
1521                name: "a",
1522                location: 4..5,
1523            }),
1524            Ast::Binary {
1525                operator: BinaryOperator::LogicalOr,
1526                rhs_len: 1,
1527                location: 2..3,
1528            },
1529        ];
1530        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(1))));
1531    }
1532
1533    #[test]
1534    fn eval_logical_or_full_evaluation() {
1535        let env = &mut HashMap::new();
1536        let ast = &[
1537            Ast::Term(Term::Value(Value::Integer(0))),
1538            Ast::Term(Term::Value(Value::Integer(2))),
1539            Ast::Binary {
1540                operator: BinaryOperator::LogicalOr,
1541                rhs_len: 1,
1542                location: 2..3,
1543            },
1544        ];
1545        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(1))));
1546
1547        let env = &mut HashMap::new();
1548        let ast = &[
1549            Ast::Term(Term::Value(Value::Integer(0))),
1550            Ast::Term(Term::Value(Value::Integer(0))),
1551            Ast::Binary {
1552                operator: BinaryOperator::LogicalOr,
1553                rhs_len: 1,
1554                location: 2..3,
1555            },
1556        ];
1557        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(0))));
1558    }
1559
1560    #[test]
1561    fn eval_logical_and_short_circuit() {
1562        let env = &mut HashMap::new();
1563        env.insert("a".to_string(), "*".to_string());
1564        let ast = &[
1565            Ast::Term(Term::Value(Value::Integer(0))),
1566            Ast::Term(Term::Variable {
1567                name: "a",
1568                location: 4..5,
1569            }),
1570            Ast::Binary {
1571                operator: BinaryOperator::LogicalAnd,
1572                rhs_len: 1,
1573                location: 2..3,
1574            },
1575        ];
1576        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(0))));
1577    }
1578
1579    #[test]
1580    fn eval_logical_and_full_evaluation() {
1581        let env = &mut HashMap::new();
1582        let ast = &[
1583            Ast::Term(Term::Value(Value::Integer(2))),
1584            Ast::Term(Term::Value(Value::Integer(3))),
1585            Ast::Binary {
1586                operator: BinaryOperator::LogicalAnd,
1587                rhs_len: 1,
1588                location: 2..3,
1589            },
1590        ];
1591        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(1))));
1592
1593        let env = &mut HashMap::new();
1594        let ast = &[
1595            Ast::Term(Term::Value(Value::Integer(2))),
1596            Ast::Term(Term::Value(Value::Integer(0))),
1597            Ast::Binary {
1598                operator: BinaryOperator::LogicalAnd,
1599                rhs_len: 1,
1600                location: 2..3,
1601            },
1602        ];
1603        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(0))));
1604    }
1605
1606    #[test]
1607    fn eval_binary() {
1608        let env = &mut HashMap::new();
1609        let ast = &[
1610            Ast::Term(Term::Value(Value::Integer(12))),
1611            Ast::Term(Term::Value(Value::Integer(34))),
1612            Ast::Binary {
1613                operator: BinaryOperator::Add,
1614                rhs_len: 1,
1615                location: 2..3,
1616            },
1617        ];
1618        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(46))));
1619    }
1620
1621    #[test]
1622    fn eval_conditional_then() {
1623        let env = &mut HashMap::new();
1624        env.insert("a".to_string(), "*".to_string());
1625        let ast = &[
1626            Ast::Term(Term::Value(Value::Integer(1))),
1627            Ast::Term(Term::Value(Value::Integer(10))),
1628            Ast::Term(Term::Variable {
1629                name: "a",
1630                location: 4..5,
1631            }),
1632            Ast::Conditional {
1633                then_len: 1,
1634                else_len: 1,
1635            },
1636        ];
1637        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(10))));
1638    }
1639
1640    #[test]
1641    fn eval_conditional_else() {
1642        let env = &mut HashMap::new();
1643        env.insert("a".to_string(), "*".to_string());
1644        let ast = &[
1645            Ast::Term(Term::Value(Value::Integer(0))),
1646            Ast::Term(Term::Variable {
1647                name: "a",
1648                location: 4..5,
1649            }),
1650            Ast::Term(Term::Value(Value::Integer(21))),
1651            Ast::Conditional {
1652                then_len: 1,
1653                else_len: 1,
1654            },
1655        ];
1656        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(21))));
1657    }
1658}