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)]
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
343        .split_last()
344        .expect("the expression should not be empty");
345    match root {
346        Ast::Term(term) => Ok(term.clone()),
347
348        Ast::Prefix { operator, location } => {
349            let term = eval(children, env)?;
350            apply_prefix(term, *operator, location, env).map(Term::Value)
351        }
352
353        Ast::Postfix { operator, location } => {
354            let term = eval(children, env)?;
355            apply_postfix(term, *operator, location, env).map(Term::Value)
356        }
357
358        Ast::Binary {
359            operator: BinaryOperator::LogicalOr,
360            rhs_len,
361            location,
362        } => {
363            let (lhs_ast, rhs_ast) = children.split_at(children.len() - rhs_len);
364            let lhs = into_value(eval(lhs_ast, env)?, env)?;
365            if lhs != Value::Integer(0) {
366                return Ok(Term::Value(Value::Integer(1)));
367            }
368            let rhs = into_value(eval(rhs_ast, env)?, env)?;
369            binary_result(lhs, rhs, BinaryOperator::LogicalOr, location).map(Term::Value)
370        }
371
372        Ast::Binary {
373            operator: BinaryOperator::LogicalAnd,
374            rhs_len,
375            location,
376        } => {
377            let (lhs_ast, rhs_ast) = children.split_at(children.len() - rhs_len);
378            let lhs = into_value(eval(lhs_ast, env)?, env)?;
379            if lhs == Value::Integer(0) {
380                return Ok(Term::Value(Value::Integer(0)));
381            }
382            let rhs = into_value(eval(rhs_ast, env)?, env)?;
383            binary_result(lhs, rhs, BinaryOperator::LogicalAnd, location).map(Term::Value)
384        }
385
386        Ast::Binary {
387            operator,
388            rhs_len,
389            location,
390        } => {
391            let (lhs_ast, rhs_ast) = children.split_at(children.len() - rhs_len);
392            let lhs = eval(lhs_ast, env)?;
393            let rhs = eval(rhs_ast, env)?;
394            apply_binary(lhs, rhs, *operator, location, env).map(Term::Value)
395        }
396
397        Ast::Conditional { then_len, else_len } => {
398            let (children_2, else_ast) = children.split_at(children.len() - else_len);
399            let (condition_ast, then_ast) = children_2.split_at(children_2.len() - then_len);
400            let condition = into_value(eval(condition_ast, env)?, env)?;
401            let result_ast = if condition != Value::Integer(0) {
402                then_ast
403            } else {
404                else_ast
405            };
406            eval(result_ast, env)
407        }
408    }
409}
410
411#[cfg(test)]
412mod tests {
413    use super::*;
414    use std::collections::HashMap;
415    use std::convert::Infallible;
416
417    #[test]
418    fn expand_variable_non_existing() {
419        let env = &mut HashMap::new();
420        assert_eq!(expand_variable("a", &(10..11), env), Ok(Value::Integer(0)));
421        assert_eq!(expand_variable("b", &(11..12), env), Ok(Value::Integer(0)));
422    }
423
424    #[test]
425    fn expand_variable_valid() {
426        let env = &mut HashMap::new();
427        env.insert("a".to_string(), "42".to_string());
428        env.insert("b".to_string(), "-123".to_string());
429        assert_eq!(expand_variable("a", &(10..11), env), Ok(Value::Integer(42)));
430        assert_eq!(
431            expand_variable("b", &(11..12), env),
432            Ok(Value::Integer(-123))
433        );
434    }
435
436    #[test]
437    fn expand_variable_invalid() {
438        let env = &mut HashMap::new();
439        env.insert("a".to_string(), "*".to_string());
440        assert_eq!(
441            expand_variable("a", &(10..11), env),
442            Err(Error {
443                cause: EvalError::InvalidVariableValue("*".to_string()),
444                location: 10..11,
445            })
446        );
447    }
448
449    #[test]
450    fn apply_prefix_increment() {
451        let env = &mut HashMap::new();
452
453        assert_eq!(
454            apply_prefix(
455                Term::Variable {
456                    name: "i",
457                    location: 6..7
458                },
459                PrefixOperator::Increment,
460                &(3..5),
461                env
462            ),
463            Ok(Value::Integer(1))
464        );
465        assert_eq!(env["i"], "1");
466
467        assert_eq!(
468            apply_prefix(
469                Term::Variable {
470                    name: "i",
471                    location: 6..7
472                },
473                PrefixOperator::Increment,
474                &(3..5),
475                env
476            ),
477            Ok(Value::Integer(2))
478        );
479        assert_eq!(env["i"], "2");
480    }
481
482    #[test]
483    fn apply_prefix_increment_overflow() {
484        let env = &mut HashMap::new();
485        env.insert("i".to_string(), "9223372036854775807".to_string());
486        assert_eq!(
487            apply_prefix(
488                Term::Variable {
489                    name: "i",
490                    location: 6..7
491                },
492                PrefixOperator::Increment,
493                &(3..5),
494                env
495            ),
496            Err(Error {
497                cause: EvalError::Overflow,
498                location: 3..5,
499            })
500        );
501    }
502
503    #[test]
504    fn apply_prefix_increment_not_variable() {
505        let env = &mut HashMap::new();
506        assert_eq!(
507            apply_prefix(
508                Term::Value(Value::Integer(3)),
509                PrefixOperator::Increment,
510                &(3..5),
511                env
512            ),
513            Err(Error {
514                cause: EvalError::AssignmentToValue,
515                location: 3..5,
516            })
517        );
518    }
519
520    #[test]
521    fn apply_prefix_decrement() {
522        let env = &mut HashMap::new();
523
524        assert_eq!(
525            apply_prefix(
526                Term::Variable {
527                    name: "i",
528                    location: 6..7
529                },
530                PrefixOperator::Decrement,
531                &(3..5),
532                env
533            ),
534            Ok(Value::Integer(-1))
535        );
536        assert_eq!(env["i"], "-1");
537
538        assert_eq!(
539            apply_prefix(
540                Term::Variable {
541                    name: "i",
542                    location: 6..7
543                },
544                PrefixOperator::Decrement,
545                &(3..5),
546                env
547            ),
548            Ok(Value::Integer(-2))
549        );
550        assert_eq!(env["i"], "-2");
551    }
552
553    #[test]
554    fn apply_prefix_decrement_overflow() {
555        let env = &mut HashMap::new();
556        env.insert("i".to_string(), "-9223372036854775808".to_string());
557        assert_eq!(
558            apply_prefix(
559                Term::Variable {
560                    name: "i",
561                    location: 6..7
562                },
563                PrefixOperator::Decrement,
564                &(3..5),
565                env
566            ),
567            Err(Error {
568                cause: EvalError::Overflow,
569                location: 3..5,
570            })
571        );
572    }
573
574    #[test]
575    fn apply_prefix_decrement_not_variable() {
576        let env = &mut HashMap::new();
577        assert_eq!(
578            apply_prefix(
579                Term::Value(Value::Integer(3)),
580                PrefixOperator::Decrement,
581                &(3..5),
582                env
583            ),
584            Err(Error {
585                cause: EvalError::AssignmentToValue,
586                location: 3..5,
587            })
588        );
589    }
590
591    #[test]
592    fn apply_prefix_numeric_coercion() {
593        let env = &mut HashMap::new();
594        env.insert("a".to_string(), "12".to_string());
595        assert_eq!(
596            apply_prefix(
597                Term::Value(Value::Integer(7)),
598                PrefixOperator::NumericCoercion,
599                &(3..4),
600                env
601            ),
602            Ok(Value::Integer(7))
603        );
604        assert_eq!(
605            apply_prefix(
606                Term::Variable {
607                    name: "a",
608                    location: 5..7,
609                },
610                PrefixOperator::NumericCoercion,
611                &(3..4),
612                env
613            ),
614            Ok(Value::Integer(12))
615        );
616    }
617
618    #[test]
619    fn apply_prefix_numeric_negation() {
620        let env = &mut HashMap::new();
621        assert_eq!(
622            apply_prefix(
623                Term::Value(Value::Integer(7)),
624                PrefixOperator::NumericNegation,
625                &(3..4),
626                env
627            ),
628            Ok(Value::Integer(-7))
629        );
630        assert_eq!(
631            apply_prefix(
632                Term::Value(Value::Integer(-10)),
633                PrefixOperator::NumericNegation,
634                &(3..4),
635                env
636            ),
637            Ok(Value::Integer(10))
638        );
639    }
640
641    #[test]
642    fn apply_prefix_numeric_negation_overflow() {
643        let env = &mut HashMap::new();
644        assert_eq!(
645            apply_prefix(
646                Term::Value(Value::Integer(i64::MIN)),
647                PrefixOperator::NumericNegation,
648                &(3..4),
649                env
650            ),
651            Err(Error {
652                cause: EvalError::Overflow,
653                location: 3..4,
654            })
655        );
656    }
657
658    #[test]
659    fn apply_prefix_logical_negation() {
660        let env = &mut HashMap::new();
661        assert_eq!(
662            apply_prefix(
663                Term::Value(Value::Integer(0)),
664                PrefixOperator::LogicalNegation,
665                &(3..4),
666                env
667            ),
668            Ok(Value::Integer(1))
669        );
670
671        for i in [-1, 1, 2, 100, i64::MAX, i64::MIN] {
672            assert_eq!(
673                apply_prefix(
674                    Term::Value(Value::Integer(i)),
675                    PrefixOperator::LogicalNegation,
676                    &(3..4),
677                    env
678                ),
679                Ok(Value::Integer(0)),
680                "i={i:?}"
681            );
682        }
683    }
684
685    #[test]
686    fn apply_prefix_bitwise_negation() {
687        let env = &mut HashMap::new();
688        assert_eq!(
689            apply_prefix(
690                Term::Value(Value::Integer(0)),
691                PrefixOperator::BitwiseNegation,
692                &(3..4),
693                env
694            ),
695            Ok(Value::Integer(!0))
696        );
697        assert_eq!(
698            apply_prefix(
699                Term::Value(Value::Integer(-10000)),
700                PrefixOperator::BitwiseNegation,
701                &(3..4),
702                env
703            ),
704            Ok(Value::Integer(!-10000))
705        );
706    }
707
708    #[test]
709    fn apply_postfix_increment() {
710        let env = &mut HashMap::new();
711
712        assert_eq!(
713            apply_postfix(
714                Term::Variable {
715                    name: "i",
716                    location: 0..1,
717                },
718                PostfixOperator::Increment,
719                &(3..5),
720                env
721            ),
722            Ok(Value::Integer(0))
723        );
724        assert_eq!(env["i"], "1");
725
726        assert_eq!(
727            apply_postfix(
728                Term::Variable {
729                    name: "i",
730                    location: 0..1,
731                },
732                PostfixOperator::Increment,
733                &(3..5),
734                env
735            ),
736            Ok(Value::Integer(1))
737        );
738        assert_eq!(env["i"], "2");
739    }
740
741    #[test]
742    fn apply_postfix_increment_overflow() {
743        let env = &mut HashMap::new();
744        env.insert("i".to_string(), "9223372036854775807".to_string());
745        assert_eq!(
746            apply_postfix(
747                Term::Variable {
748                    name: "i",
749                    location: 0..1,
750                },
751                PostfixOperator::Increment,
752                &(3..5),
753                env
754            ),
755            Err(Error {
756                cause: EvalError::Overflow,
757                location: 3..5,
758            })
759        );
760    }
761
762    #[test]
763    fn apply_postfix_increment_not_variable() {
764        let env = &mut HashMap::new();
765        assert_eq!(
766            apply_postfix(
767                Term::Value(Value::Integer(13)),
768                PostfixOperator::Increment,
769                &(3..5),
770                env
771            ),
772            Err(Error {
773                cause: EvalError::AssignmentToValue,
774                location: 3..5,
775            })
776        );
777    }
778
779    #[test]
780    fn apply_postfix_decrement() {
781        let env = &mut HashMap::new();
782
783        assert_eq!(
784            apply_postfix(
785                Term::Variable {
786                    name: "i",
787                    location: 0..1,
788                },
789                PostfixOperator::Decrement,
790                &(3..5),
791                env
792            ),
793            Ok(Value::Integer(0))
794        );
795        assert_eq!(env["i"], "-1");
796
797        assert_eq!(
798            apply_postfix(
799                Term::Variable {
800                    name: "i",
801                    location: 0..1,
802                },
803                PostfixOperator::Decrement,
804                &(3..5),
805                env
806            ),
807            Ok(Value::Integer(-1))
808        );
809        assert_eq!(env["i"], "-2");
810    }
811
812    #[test]
813    fn apply_postfix_decrement_overflow() {
814        let env = &mut HashMap::new();
815        env.insert("i".to_string(), "-9223372036854775808".to_string());
816        assert_eq!(
817            apply_postfix(
818                Term::Variable {
819                    name: "i",
820                    location: 0..1,
821                },
822                PostfixOperator::Decrement,
823                &(3..5),
824                env
825            ),
826            Err(Error {
827                cause: EvalError::Overflow,
828                location: 3..5,
829            })
830        );
831    }
832
833    #[test]
834    fn apply_postfix_decrement_not_variable() {
835        let env = &mut HashMap::new();
836        assert_eq!(
837            apply_postfix(
838                Term::Value(Value::Integer(13)),
839                PostfixOperator::Decrement,
840                &(3..5),
841                env
842            ),
843            Err(Error {
844                cause: EvalError::AssignmentToValue,
845                location: 3..5,
846            })
847        );
848    }
849
850    #[test]
851    fn binary_result_logical_or() {
852        let zero = Value::Integer(0);
853        let one = Value::Integer(1);
854        let two = Value::Integer(2);
855        let operator = BinaryOperator::LogicalOr;
856        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
857        assert_eq!(result, Ok(Value::Integer(0)));
858        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
859        assert_eq!(result, Ok(Value::Integer(1)));
860        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
861        assert_eq!(result, Ok(Value::Integer(1)));
862        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
863        assert_eq!(result, Ok(Value::Integer(1)));
864    }
865
866    #[test]
867    fn binary_result_logical_and() {
868        let zero = Value::Integer(0);
869        let one = Value::Integer(1);
870        let two = Value::Integer(2);
871        let operator = BinaryOperator::LogicalAnd;
872        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
873        assert_eq!(result, Ok(Value::Integer(0)));
874        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
875        assert_eq!(result, Ok(Value::Integer(0)));
876        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
877        assert_eq!(result, Ok(Value::Integer(1)));
878        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
879        assert_eq!(result, Ok(Value::Integer(0)));
880    }
881
882    #[test]
883    fn binary_result_bitwise_or() {
884        let zero = Value::Integer(0);
885        let three = Value::Integer(3);
886        let six = Value::Integer(6);
887        for operator in [BinaryOperator::BitwiseOr, BinaryOperator::BitwiseOrAssign] {
888            let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..4));
889            assert_eq!(result, Ok(Value::Integer(0)));
890            let result = binary_result::<Infallible, Infallible>(three, zero, operator, &(3..4));
891            assert_eq!(result, Ok(Value::Integer(3)));
892            let result = binary_result::<Infallible, Infallible>(three, six, operator, &(3..4));
893            assert_eq!(result, Ok(Value::Integer(7)));
894            let result = binary_result::<Infallible, Infallible>(zero, six, operator, &(3..4));
895            assert_eq!(result, Ok(Value::Integer(6)));
896        }
897    }
898
899    #[test]
900    fn binary_result_bitwise_xor() {
901        let zero = Value::Integer(0);
902        let three = Value::Integer(3);
903        let six = Value::Integer(6);
904        for operator in [BinaryOperator::BitwiseXor, BinaryOperator::BitwiseXorAssign] {
905            let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..4));
906            assert_eq!(result, Ok(Value::Integer(0)));
907            let result = binary_result::<Infallible, Infallible>(three, zero, operator, &(3..4));
908            assert_eq!(result, Ok(Value::Integer(3)));
909            let result = binary_result::<Infallible, Infallible>(three, six, operator, &(3..4));
910            assert_eq!(result, Ok(Value::Integer(5)));
911            let result = binary_result::<Infallible, Infallible>(zero, six, operator, &(3..4));
912            assert_eq!(result, Ok(Value::Integer(6)));
913        }
914    }
915
916    #[test]
917    fn binary_result_bitwise_and() {
918        let zero = Value::Integer(0);
919        let three = Value::Integer(3);
920        let six = Value::Integer(6);
921        for operator in [BinaryOperator::BitwiseAnd, BinaryOperator::BitwiseAndAssign] {
922            let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..4));
923            assert_eq!(result, Ok(Value::Integer(0)));
924            let result = binary_result::<Infallible, Infallible>(three, zero, operator, &(3..4));
925            assert_eq!(result, Ok(Value::Integer(0)));
926            let result = binary_result::<Infallible, Infallible>(three, six, operator, &(3..4));
927            assert_eq!(result, Ok(Value::Integer(2)));
928            let result = binary_result::<Infallible, Infallible>(zero, six, operator, &(3..4));
929            assert_eq!(result, Ok(Value::Integer(0)));
930        }
931    }
932
933    #[test]
934    fn binary_result_equal_to() {
935        let zero = Value::Integer(0);
936        let one = Value::Integer(1);
937        let two = Value::Integer(2);
938        let operator = BinaryOperator::EqualTo;
939        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
940        assert_eq!(result, Ok(Value::Integer(1)));
941        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
942        assert_eq!(result, Ok(Value::Integer(1)));
943        let result = binary_result::<Infallible, Infallible>(two, two, operator, &(3..5));
944        assert_eq!(result, Ok(Value::Integer(1)));
945        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
946        assert_eq!(result, Ok(Value::Integer(0)));
947        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
948        assert_eq!(result, Ok(Value::Integer(0)));
949        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
950        assert_eq!(result, Ok(Value::Integer(0)));
951    }
952
953    #[test]
954    fn binary_result_not_equal_to() {
955        let zero = Value::Integer(0);
956        let one = Value::Integer(1);
957        let two = Value::Integer(2);
958        let operator = BinaryOperator::NotEqualTo;
959        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
960        assert_eq!(result, Ok(Value::Integer(0)));
961        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
962        assert_eq!(result, Ok(Value::Integer(0)));
963        let result = binary_result::<Infallible, Infallible>(two, two, operator, &(3..5));
964        assert_eq!(result, Ok(Value::Integer(0)));
965        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
966        assert_eq!(result, Ok(Value::Integer(1)));
967        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
968        assert_eq!(result, Ok(Value::Integer(1)));
969        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
970        assert_eq!(result, Ok(Value::Integer(1)));
971    }
972
973    #[test]
974    fn binary_result_less_than() {
975        let zero = Value::Integer(0);
976        let one = Value::Integer(1);
977        let two = Value::Integer(2);
978        let operator = BinaryOperator::LessThan;
979        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
980        assert_eq!(result, Ok(Value::Integer(0)));
981        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
982        assert_eq!(result, Ok(Value::Integer(0)));
983        let result = binary_result::<Infallible, Infallible>(two, two, operator, &(3..5));
984        assert_eq!(result, Ok(Value::Integer(0)));
985        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
986        assert_eq!(result, Ok(Value::Integer(0)));
987        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
988        assert_eq!(result, Ok(Value::Integer(1)));
989        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
990        assert_eq!(result, Ok(Value::Integer(1)));
991    }
992
993    #[test]
994    fn binary_result_greater_than() {
995        let zero = Value::Integer(0);
996        let one = Value::Integer(1);
997        let two = Value::Integer(2);
998        let operator = BinaryOperator::GreaterThan;
999        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
1000        assert_eq!(result, Ok(Value::Integer(0)));
1001        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
1002        assert_eq!(result, Ok(Value::Integer(0)));
1003        let result = binary_result::<Infallible, Infallible>(two, one, operator, &(3..5));
1004        assert_eq!(result, Ok(Value::Integer(1)));
1005        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
1006        assert_eq!(result, Ok(Value::Integer(1)));
1007        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
1008        assert_eq!(result, Ok(Value::Integer(0)));
1009        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
1010        assert_eq!(result, Ok(Value::Integer(0)));
1011    }
1012
1013    #[test]
1014    fn binary_result_less_than_or_equal_to() {
1015        let zero = Value::Integer(0);
1016        let one = Value::Integer(1);
1017        let two = Value::Integer(2);
1018        let operator = BinaryOperator::LessThanOrEqualTo;
1019        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
1020        assert_eq!(result, Ok(Value::Integer(1)));
1021        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
1022        assert_eq!(result, Ok(Value::Integer(1)));
1023        let result = binary_result::<Infallible, Infallible>(two, one, operator, &(3..5));
1024        assert_eq!(result, Ok(Value::Integer(0)));
1025        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
1026        assert_eq!(result, Ok(Value::Integer(0)));
1027        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
1028        assert_eq!(result, Ok(Value::Integer(1)));
1029        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
1030        assert_eq!(result, Ok(Value::Integer(1)));
1031    }
1032
1033    #[test]
1034    fn binary_result_greater_than_or_equal_to() {
1035        let zero = Value::Integer(0);
1036        let one = Value::Integer(1);
1037        let two = Value::Integer(2);
1038        let operator = BinaryOperator::GreaterThanOrEqualTo;
1039        let result = binary_result::<Infallible, Infallible>(zero, zero, operator, &(3..5));
1040        assert_eq!(result, Ok(Value::Integer(1)));
1041        let result = binary_result::<Infallible, Infallible>(one, one, operator, &(3..5));
1042        assert_eq!(result, Ok(Value::Integer(1)));
1043        let result = binary_result::<Infallible, Infallible>(two, one, operator, &(3..5));
1044        assert_eq!(result, Ok(Value::Integer(1)));
1045        let result = binary_result::<Infallible, Infallible>(one, zero, operator, &(3..5));
1046        assert_eq!(result, Ok(Value::Integer(1)));
1047        let result = binary_result::<Infallible, Infallible>(one, two, operator, &(3..5));
1048        assert_eq!(result, Ok(Value::Integer(0)));
1049        let result = binary_result::<Infallible, Infallible>(zero, two, operator, &(3..5));
1050        assert_eq!(result, Ok(Value::Integer(0)));
1051    }
1052
1053    #[test]
1054    fn binary_result_shift_left() {
1055        let lhs = Value::Integer(0x94E239);
1056        let rhs = Value::Integer(7);
1057        for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1058            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1059            assert_eq!(result, Ok(Value::Integer(0x94E239 << 7)));
1060        }
1061    }
1062
1063    #[test]
1064    fn binary_result_shift_left_negative_lhs() {
1065        let lhs = Value::Integer(-1);
1066        let rhs = Value::Integer(0);
1067        for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1068            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1069            assert_eq!(
1070                result,
1071                Err(Error {
1072                    cause: EvalError::LeftShiftingNegative,
1073                    location: 3..4,
1074                })
1075            );
1076        }
1077    }
1078
1079    #[test]
1080    fn binary_result_shift_left_negative_rhs() {
1081        let lhs = Value::Integer(0);
1082        let rhs = Value::Integer(-1);
1083        for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1084            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1085            assert_eq!(
1086                result,
1087                Err(Error {
1088                    cause: EvalError::ReverseShifting,
1089                    location: 3..4,
1090                })
1091            );
1092        }
1093    }
1094
1095    #[test]
1096    fn binary_result_shift_left_too_large_rhs() {
1097        let lhs = Value::Integer(0);
1098        for rhs in [i64::BITS as i64, i64::MAX] {
1099            let rhs = Value::Integer(rhs);
1100            for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1101                let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1102                assert_eq!(
1103                    result,
1104                    Err(Error {
1105                        cause: EvalError::Overflow,
1106                        location: 3..4,
1107                    })
1108                );
1109            }
1110        }
1111    }
1112
1113    #[test]
1114    fn binary_result_shift_left_overflow_to_sign_bit() {
1115        let lhs = Value::Integer(0x4000_0000_0000_0000);
1116        let rhs = Value::Integer(1);
1117        for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1118            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1119            assert_eq!(
1120                result,
1121                Err(Error {
1122                    cause: EvalError::Overflow,
1123                    location: 3..4,
1124                })
1125            );
1126        }
1127    }
1128
1129    #[test]
1130    fn binary_result_shift_left_overflow_beyond_sign_bit() {
1131        let lhs = Value::Integer(0x4000_0000_0000_0000);
1132        let rhs = Value::Integer(2);
1133        for operator in [BinaryOperator::ShiftLeft, BinaryOperator::ShiftLeftAssign] {
1134            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1135            assert_eq!(
1136                result,
1137                Err(Error {
1138                    cause: EvalError::Overflow,
1139                    location: 3..4,
1140                })
1141            );
1142        }
1143    }
1144
1145    #[test]
1146    fn binary_result_shift_right() {
1147        let lhs = Value::Integer(0x94E239);
1148        let rhs = Value::Integer(7);
1149        for operator in [BinaryOperator::ShiftRight, BinaryOperator::ShiftRightAssign] {
1150            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1151            assert_eq!(result, Ok(Value::Integer(0x94E239 >> 7)));
1152        }
1153    }
1154
1155    #[test]
1156    fn binary_result_shift_right_negative_rhs() {
1157        let lhs = Value::Integer(0);
1158        let rhs = Value::Integer(-1);
1159        for operator in [BinaryOperator::ShiftRight, BinaryOperator::ShiftRightAssign] {
1160            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1161            assert_eq!(
1162                result,
1163                Err(Error {
1164                    cause: EvalError::ReverseShifting,
1165                    location: 3..4,
1166                })
1167            );
1168        }
1169    }
1170
1171    #[test]
1172    fn binary_result_shift_right_too_large_rhs() {
1173        let lhs = Value::Integer(0);
1174        let rhs = Value::Integer(i64::BITS as _);
1175        for operator in [BinaryOperator::ShiftRight, BinaryOperator::ShiftRightAssign] {
1176            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1177            assert_eq!(
1178                result,
1179                Err(Error {
1180                    cause: EvalError::Overflow,
1181                    location: 3..4,
1182                })
1183            );
1184        }
1185    }
1186
1187    #[test]
1188    fn binary_result_add() {
1189        let lhs = Value::Integer(15);
1190        let rhs = Value::Integer(27);
1191        for operator in [BinaryOperator::Add, BinaryOperator::AddAssign] {
1192            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1193            assert_eq!(result, Ok(Value::Integer(42)));
1194        }
1195    }
1196
1197    #[test]
1198    fn binary_result_add_overflow() {
1199        let lhs = Value::Integer(i64::MIN);
1200        let rhs = Value::Integer(-1);
1201        for operator in [BinaryOperator::Add, BinaryOperator::AddAssign] {
1202            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1203            assert_eq!(
1204                result,
1205                Err(Error {
1206                    cause: EvalError::Overflow,
1207                    location: 3..4,
1208                })
1209            );
1210        }
1211    }
1212
1213    #[test]
1214    fn binary_result_subtract() {
1215        let lhs = Value::Integer(15);
1216        let rhs = Value::Integer(27);
1217        for operator in [BinaryOperator::Subtract, BinaryOperator::SubtractAssign] {
1218            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1219            assert_eq!(result, Ok(Value::Integer(-12)));
1220        }
1221    }
1222
1223    #[test]
1224    fn binary_result_subtract_overflow() {
1225        let lhs = Value::Integer(i64::MAX);
1226        let rhs = Value::Integer(-1);
1227        for operator in [BinaryOperator::Subtract, BinaryOperator::SubtractAssign] {
1228            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1229            assert_eq!(
1230                result,
1231                Err(Error {
1232                    cause: EvalError::Overflow,
1233                    location: 3..4,
1234                })
1235            );
1236        }
1237    }
1238
1239    #[test]
1240    fn binary_result_multiply() {
1241        let lhs = Value::Integer(15);
1242        let rhs = Value::Integer(27);
1243        for operator in [BinaryOperator::Multiply, BinaryOperator::MultiplyAssign] {
1244            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1245            assert_eq!(result, Ok(Value::Integer(405)));
1246        }
1247    }
1248
1249    #[test]
1250    fn binary_result_multiply_overflow() {
1251        let lhs = Value::Integer(0x4000_0000_0000_0000);
1252        let rhs = Value::Integer(2);
1253        for operator in [BinaryOperator::Multiply, BinaryOperator::MultiplyAssign] {
1254            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1255            assert_eq!(
1256                result,
1257                Err(Error {
1258                    cause: EvalError::Overflow,
1259                    location: 3..4,
1260                })
1261            );
1262        }
1263    }
1264
1265    #[test]
1266    fn binary_result_divide() {
1267        let lhs = Value::Integer(268);
1268        let rhs = Value::Integer(17);
1269        for operator in [BinaryOperator::Divide, BinaryOperator::DivideAssign] {
1270            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1271            assert_eq!(result, Ok(Value::Integer(15)));
1272        }
1273    }
1274
1275    #[test]
1276    fn binary_result_divide_overflow() {
1277        let lhs = Value::Integer(i64::MIN);
1278        let rhs = Value::Integer(-1);
1279        for operator in [BinaryOperator::Divide, BinaryOperator::DivideAssign] {
1280            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1281            assert_eq!(
1282                result,
1283                Err(Error {
1284                    cause: EvalError::Overflow,
1285                    location: 3..4,
1286                })
1287            );
1288        }
1289    }
1290
1291    #[test]
1292    fn binary_result_divide_by_zero() {
1293        let lhs = Value::Integer(1);
1294        let rhs = Value::Integer(0);
1295        for operator in [BinaryOperator::Divide, BinaryOperator::DivideAssign] {
1296            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1297            assert_eq!(
1298                result,
1299                Err(Error {
1300                    cause: EvalError::DivisionByZero,
1301                    location: 3..4,
1302                })
1303            );
1304        }
1305    }
1306
1307    #[test]
1308    fn binary_result_remainder() {
1309        let lhs = Value::Integer(268);
1310        let rhs = Value::Integer(17);
1311        for operator in [BinaryOperator::Remainder, BinaryOperator::RemainderAssign] {
1312            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1313            assert_eq!(result, Ok(Value::Integer(13)));
1314        }
1315    }
1316
1317    #[test]
1318    fn binary_result_remainder_overflow() {
1319        let lhs = Value::Integer(i64::MIN);
1320        let rhs = Value::Integer(-1);
1321        for operator in [BinaryOperator::Remainder, BinaryOperator::RemainderAssign] {
1322            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1323            assert_eq!(
1324                result,
1325                Err(Error {
1326                    cause: EvalError::Overflow,
1327                    location: 3..4,
1328                })
1329            );
1330        }
1331    }
1332
1333    #[test]
1334    fn binary_result_remainder_by_zero() {
1335        let lhs = Value::Integer(1);
1336        let rhs = Value::Integer(0);
1337        for operator in [BinaryOperator::Remainder, BinaryOperator::RemainderAssign] {
1338            let result = binary_result::<Infallible, Infallible>(lhs, rhs, operator, &(3..4));
1339            assert_eq!(
1340                result,
1341                Err(Error {
1342                    cause: EvalError::DivisionByZero,
1343                    location: 3..4,
1344                })
1345            );
1346        }
1347    }
1348
1349    #[test]
1350    fn apply_binary_add() {
1351        let env = &mut HashMap::new();
1352        let lhs = Term::Value(Value::Integer(30));
1353        let rhs = Term::Value(Value::Integer(12));
1354        let operator = BinaryOperator::Add;
1355        let op_location = 4..5;
1356        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1357        assert_eq!(result, Ok(Value::Integer(42)));
1358    }
1359
1360    #[test]
1361    fn apply_binary_add_overflow() {
1362        let env = &mut HashMap::new();
1363        let lhs = Term::Value(Value::Integer(i64::MAX));
1364        let rhs = Term::Value(Value::Integer(1));
1365        let operator = BinaryOperator::Add;
1366        let op_location = 4..5;
1367        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1368        assert_eq!(
1369            result,
1370            Err(Error {
1371                cause: EvalError::Overflow,
1372                location: 4..5,
1373            })
1374        );
1375    }
1376
1377    #[test]
1378    fn apply_binary_subtract() {
1379        let env = &mut HashMap::new();
1380        let lhs = Term::Value(Value::Integer(30));
1381        let rhs = Term::Value(Value::Integer(12));
1382        let operator = BinaryOperator::Subtract;
1383        let op_location = 4..5;
1384        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1385        assert_eq!(result, Ok(Value::Integer(18)));
1386    }
1387
1388    #[test]
1389    fn apply_binary_subtract_overflow() {
1390        let env = &mut HashMap::new();
1391        let lhs = Term::Value(Value::Integer(i64::MIN));
1392        let rhs = Term::Value(Value::Integer(1));
1393        let operator = BinaryOperator::Subtract;
1394        let op_location = 4..5;
1395        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1396        assert_eq!(
1397            result,
1398            Err(Error {
1399                cause: EvalError::Overflow,
1400                location: 4..5,
1401            })
1402        );
1403    }
1404
1405    #[test]
1406    fn apply_binary_assign() {
1407        let env = &mut HashMap::new();
1408        let lhs = Term::Variable {
1409            name: "foo",
1410            location: 1..4,
1411        };
1412        let rhs = Term::Value(Value::Integer(42));
1413        let operator = BinaryOperator::Assign;
1414        let op_location = 4..5;
1415        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1416        assert_eq!(result, Ok(Value::Integer(42)));
1417        assert_eq!(env["foo"], "42");
1418    }
1419
1420    #[test]
1421    fn apply_binary_assign_not_variable() {
1422        let env = &mut HashMap::new();
1423        let lhs = Term::Value(Value::Integer(3));
1424        let rhs = Term::Value(Value::Integer(42));
1425        let operator = BinaryOperator::Assign;
1426        let op_location = 4..5;
1427        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1428        assert_eq!(
1429            result,
1430            Err(Error {
1431                cause: EvalError::AssignmentToValue,
1432                location: 4..5,
1433            })
1434        );
1435    }
1436
1437    #[test]
1438    fn apply_binary_add_assign() {
1439        let env = &mut HashMap::new();
1440        env.insert("a".to_string(), "10".to_string());
1441        let lhs = Term::Variable {
1442            name: "a",
1443            location: 1..2,
1444        };
1445        let rhs = Term::Value(Value::Integer(32));
1446        let operator = BinaryOperator::AddAssign;
1447        let op_location = 4..6;
1448        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1449        assert_eq!(result, Ok(Value::Integer(42)));
1450        assert_eq!(env["a"], "42");
1451    }
1452
1453    #[test]
1454    fn apply_binary_add_assign_not_variable() {
1455        let env = &mut HashMap::new();
1456        let lhs = Term::Value(Value::Integer(3));
1457        let rhs = Term::Value(Value::Integer(42));
1458        let operator = BinaryOperator::AddAssign;
1459        let op_location = 4..6;
1460        let result = apply_binary(lhs, rhs, operator, &op_location, env);
1461        assert_eq!(
1462            result,
1463            Err(Error {
1464                cause: EvalError::AssignmentToValue,
1465                location: 4..6,
1466            })
1467        );
1468    }
1469
1470    #[test]
1471    fn eval_term() {
1472        let env = &mut HashMap::new();
1473
1474        let t = Term::Value(Value::Integer(42));
1475        assert_eq!(eval(&[Ast::Term(t.clone())], env), Ok(t));
1476
1477        let t = Term::Variable {
1478            name: "a",
1479            location: 10..11,
1480        };
1481        assert_eq!(eval(&[Ast::Term(t.clone())], env), Ok(t));
1482    }
1483
1484    #[test]
1485    fn eval_prefix() {
1486        let env = &mut HashMap::new();
1487        let ast = &[
1488            Ast::Term(Term::Value(Value::Integer(15))),
1489            Ast::Prefix {
1490                operator: PrefixOperator::NumericNegation,
1491                location: 2..3,
1492            },
1493        ];
1494        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(-15))));
1495    }
1496
1497    #[test]
1498    fn eval_postfix() {
1499        let env = &mut HashMap::new();
1500        let ast = &[
1501            Ast::Term(Term::Variable {
1502                name: "x",
1503                location: 0..1,
1504            }),
1505            Ast::Postfix {
1506                operator: PostfixOperator::Increment,
1507                location: 1..3,
1508            },
1509        ];
1510        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(0))));
1511    }
1512
1513    #[test]
1514    fn eval_logical_or_short_circuit() {
1515        let env = &mut HashMap::new();
1516        env.insert("a".to_string(), "*".to_string());
1517        let ast = &[
1518            Ast::Term(Term::Value(Value::Integer(-1))),
1519            Ast::Term(Term::Variable {
1520                name: "a",
1521                location: 4..5,
1522            }),
1523            Ast::Binary {
1524                operator: BinaryOperator::LogicalOr,
1525                rhs_len: 1,
1526                location: 2..3,
1527            },
1528        ];
1529        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(1))));
1530    }
1531
1532    #[test]
1533    fn eval_logical_or_full_evaluation() {
1534        let env = &mut HashMap::new();
1535        let ast = &[
1536            Ast::Term(Term::Value(Value::Integer(0))),
1537            Ast::Term(Term::Value(Value::Integer(2))),
1538            Ast::Binary {
1539                operator: BinaryOperator::LogicalOr,
1540                rhs_len: 1,
1541                location: 2..3,
1542            },
1543        ];
1544        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(1))));
1545
1546        let env = &mut HashMap::new();
1547        let ast = &[
1548            Ast::Term(Term::Value(Value::Integer(0))),
1549            Ast::Term(Term::Value(Value::Integer(0))),
1550            Ast::Binary {
1551                operator: BinaryOperator::LogicalOr,
1552                rhs_len: 1,
1553                location: 2..3,
1554            },
1555        ];
1556        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(0))));
1557    }
1558
1559    #[test]
1560    fn eval_logical_and_short_circuit() {
1561        let env = &mut HashMap::new();
1562        env.insert("a".to_string(), "*".to_string());
1563        let ast = &[
1564            Ast::Term(Term::Value(Value::Integer(0))),
1565            Ast::Term(Term::Variable {
1566                name: "a",
1567                location: 4..5,
1568            }),
1569            Ast::Binary {
1570                operator: BinaryOperator::LogicalAnd,
1571                rhs_len: 1,
1572                location: 2..3,
1573            },
1574        ];
1575        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(0))));
1576    }
1577
1578    #[test]
1579    fn eval_logical_and_full_evaluation() {
1580        let env = &mut HashMap::new();
1581        let ast = &[
1582            Ast::Term(Term::Value(Value::Integer(2))),
1583            Ast::Term(Term::Value(Value::Integer(3))),
1584            Ast::Binary {
1585                operator: BinaryOperator::LogicalAnd,
1586                rhs_len: 1,
1587                location: 2..3,
1588            },
1589        ];
1590        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(1))));
1591
1592        let env = &mut HashMap::new();
1593        let ast = &[
1594            Ast::Term(Term::Value(Value::Integer(2))),
1595            Ast::Term(Term::Value(Value::Integer(0))),
1596            Ast::Binary {
1597                operator: BinaryOperator::LogicalAnd,
1598                rhs_len: 1,
1599                location: 2..3,
1600            },
1601        ];
1602        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(0))));
1603    }
1604
1605    #[test]
1606    fn eval_binary() {
1607        let env = &mut HashMap::new();
1608        let ast = &[
1609            Ast::Term(Term::Value(Value::Integer(12))),
1610            Ast::Term(Term::Value(Value::Integer(34))),
1611            Ast::Binary {
1612                operator: BinaryOperator::Add,
1613                rhs_len: 1,
1614                location: 2..3,
1615            },
1616        ];
1617        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(46))));
1618    }
1619
1620    #[test]
1621    fn eval_conditional_then() {
1622        let env = &mut HashMap::new();
1623        env.insert("a".to_string(), "*".to_string());
1624        let ast = &[
1625            Ast::Term(Term::Value(Value::Integer(1))),
1626            Ast::Term(Term::Value(Value::Integer(10))),
1627            Ast::Term(Term::Variable {
1628                name: "a",
1629                location: 4..5,
1630            }),
1631            Ast::Conditional {
1632                then_len: 1,
1633                else_len: 1,
1634            },
1635        ];
1636        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(10))));
1637    }
1638
1639    #[test]
1640    fn eval_conditional_else() {
1641        let env = &mut HashMap::new();
1642        env.insert("a".to_string(), "*".to_string());
1643        let ast = &[
1644            Ast::Term(Term::Value(Value::Integer(0))),
1645            Ast::Term(Term::Variable {
1646                name: "a",
1647                location: 4..5,
1648            }),
1649            Ast::Term(Term::Value(Value::Integer(21))),
1650            Ast::Conditional {
1651                then_len: 1,
1652                else_len: 1,
1653            },
1654        ];
1655        assert_eq!(eval(ast, env), Ok(Term::Value(Value::Integer(21))));
1656    }
1657}