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