1use std::fmt::Debug;
37use std::ops::Range;
38use thiserror::Error;
39
40mod token;
41
42use token::PeekableTokens;
43pub use token::TokenError;
44pub use token::Value;
45
46mod ast;
47
48pub use ast::PortabilityError;
49pub use ast::SyntaxError;
50
51mod env;
52
53pub use env::Env;
54
55mod eval;
56
57pub use eval::EvalError;
58
59#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
61#[non_exhaustive]
62pub struct Config {
63 pub portable: bool,
69}
70
71impl Config {
72 #[inline]
74 #[must_use]
75 pub fn new() -> Self {
76 Self::default()
77 }
78}
79
80#[derive(Clone, Debug, Eq, Error, Hash, PartialEq)]
82#[error(transparent)]
83#[non_exhaustive]
84pub enum ErrorCause<E1, E2> {
85 SyntaxError(#[from] SyntaxError),
87 PortabilityError(#[from] PortabilityError),
89 EvalError(#[from] EvalError<E1, E2>),
91}
92
93impl<E1, E2> From<TokenError> for ErrorCause<E1, E2> {
94 fn from(e: TokenError) -> Self {
95 ErrorCause::SyntaxError(e.into())
96 }
97}
98
99#[derive(Clone, Debug, Eq, Error, Hash, PartialEq)]
101#[error("{cause}")]
102pub struct Error<E1, E2> {
103 pub cause: ErrorCause<E1, E2>,
105 pub location: Range<usize>,
107}
108
109impl<E1, E2> From<ast::Error> for Error<E1, E2> {
110 fn from(e: ast::Error) -> Self {
111 Error {
112 cause: e.cause.into(),
113 location: e.location,
114 }
115 }
116}
117
118impl<E1, E2> From<ast::portability::Error> for Error<E1, E2> {
119 fn from(e: ast::portability::Error) -> Self {
120 Error {
121 cause: e.cause.into(),
122 location: e.location,
123 }
124 }
125}
126
127impl<E1, E2> From<eval::Error<E1, E2>> for Error<E1, E2> {
128 fn from(e: eval::Error<E1, E2>) -> Self {
129 Error {
130 cause: e.cause.into(),
131 location: e.location,
132 }
133 }
134}
135
136pub fn eval_with_config<E: Env>(
138 expression: &str,
139 env: &mut E,
140 config: Config,
141) -> Result<Value, Error<E::GetVariableError, E::AssignVariableError>> {
142 let tokens = PeekableTokens::from(expression);
143 let ast = ast::parse(tokens)?;
144 if config.portable {
145 ast::portability::check(&ast)?;
146 }
147 let term = eval::eval(&ast, env)?;
148 let value = eval::into_value(term, env)?;
149 Ok(value)
150}
151
152pub fn eval<E: Env>(
154 expression: &str,
155 env: &mut E,
156) -> Result<Value, Error<E::GetVariableError, E::AssignVariableError>> {
157 eval_with_config(expression, env, Config::default())
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use std::collections::HashMap;
164
165 #[test]
166 fn eval_with_portable_config_rejects_before_evaluation() {
167 let mut env = HashMap::from([("foo".to_owned(), "41".to_owned())]);
168 let config = Config { portable: true };
169
170 assert_eq!(
171 eval_with_config("foo++", &mut env, config),
172 Err(Error {
173 cause: ErrorCause::PortabilityError(PortabilityError::IncrementDecrement),
174 location: 3..5,
175 })
176 );
177 assert_eq!(env["foo"], "41");
178 }
179
180 #[test]
181 fn decimal_integer_constants() {
182 let env = &mut HashMap::new();
183 assert_eq!(eval("1", env), Ok(Value::Integer(1)));
184 assert_eq!(eval("42", env), Ok(Value::Integer(42)));
185 }
186
187 #[test]
188 fn octal_integer_constants() {
189 let env = &mut HashMap::new();
190 assert_eq!(eval("0", env), Ok(Value::Integer(0)));
191 assert_eq!(eval("01", env), Ok(Value::Integer(1)));
192 assert_eq!(eval("07", env), Ok(Value::Integer(7)));
193 assert_eq!(eval("0123", env), Ok(Value::Integer(0o123)));
194 }
195
196 #[test]
197 fn invalid_digit_in_octal_constant() {
198 let env = &mut HashMap::new();
199 assert_eq!(
200 eval("08", env),
201 Err(Error {
202 cause: TokenError::InvalidNumericConstant.into(),
203 location: 0..2,
204 })
205 );
206 assert_eq!(
207 eval("0192", env),
208 Err(Error {
209 cause: TokenError::InvalidNumericConstant.into(),
210 location: 0..4,
211 })
212 );
213 }
214
215 #[test]
216 fn space_around_token() {
217 let env = &mut HashMap::new();
218 assert_eq!(eval(" 12", env), Ok(Value::Integer(12)));
219 assert_eq!(eval("12 ", env), Ok(Value::Integer(12)));
220 assert_eq!(eval("\n 123 \t", env), Ok(Value::Integer(123)));
221 }
223
224 #[test]
225 fn unset_variable() {
226 let env = &mut HashMap::new();
227 assert_eq!(eval("foo", env), Ok(Value::Integer(0)));
228 assert_eq!(eval("bar", env), Ok(Value::Integer(0)));
229 }
230
231 #[test]
232 fn integer_variable() {
233 let env = &mut HashMap::new();
234 env.insert("foo".to_string(), "42".to_string());
235 env.insert("bar".to_string(), "123".to_string());
236 assert_eq!(eval("foo", env), Ok(Value::Integer(42)));
237 assert_eq!(eval("bar", env), Ok(Value::Integer(123)));
238 }
239
240 #[test]
243 fn invalid_variable_value() {
244 let env = &mut HashMap::new();
245 env.insert("foo".to_string(), "".to_string());
246 env.insert("bar".to_string(), "*".to_string());
247 env.insert("oops".to_string(), "foo".to_string());
248 assert_eq!(
249 eval("foo", env),
250 Err(Error {
251 cause: EvalError::InvalidVariableValue("".to_string()).into(),
252 location: 0..3,
253 })
254 );
255 assert_eq!(
256 eval("bar", env),
257 Err(Error {
258 cause: EvalError::InvalidVariableValue("*".to_string()).into(),
259 location: 0..3,
260 })
261 );
262 assert_eq!(
263 eval(" oops ", env),
264 Err(Error {
265 cause: EvalError::InvalidVariableValue("foo".to_string()).into(),
266 location: 2..6,
267 })
268 );
269 }
270
271 #[test]
272 fn unevaluated_variable_value() {
273 let env = &mut HashMap::new();
274 env.insert("empty".to_string(), "".to_string());
275 assert_eq!(eval("1 || empty", env), Ok(Value::Integer(1)));
276 assert_eq!(eval("0 && empty++", env), Ok(Value::Integer(0)));
277 assert_eq!(eval("1 ? 2 : --empty", env), Ok(Value::Integer(2)));
278 assert_eq!(eval("0 ? empty /= 1 : 3", env), Ok(Value::Integer(3)));
279 }
280
281 #[test]
282 fn simple_assignment_operator() {
283 let env = &mut HashMap::new();
284 env.insert("foo".to_string(), "#ignored_value#".to_string());
285
286 assert_eq!(eval("a=1", env), Ok(Value::Integer(1)));
287 assert_eq!(eval(" foo = 42 ", env), Ok(Value::Integer(42)));
288
289 assert_eq!(env["a"], "1");
290 assert_eq!(env["foo"], "42");
291 assert_eq!(env.len(), 2);
292 }
293
294 #[test]
295 fn compound_assignment_operators() {
296 let env = &mut HashMap::new();
297 assert_eq!(eval("a|=1", env), Ok(Value::Integer(1)));
298 assert_eq!(eval("a^=7", env), Ok(Value::Integer(6)));
299 assert_eq!(eval("a&=3", env), Ok(Value::Integer(2)));
300 assert_eq!(eval("a<<=4", env), Ok(Value::Integer(32)));
301 assert_eq!(eval("a>>=2", env), Ok(Value::Integer(8)));
302 assert_eq!(eval("a+=1", env), Ok(Value::Integer(9)));
303 assert_eq!(eval("a-=4", env), Ok(Value::Integer(5)));
304 assert_eq!(eval("a*=21", env), Ok(Value::Integer(105)));
305 assert_eq!(eval("a/=8", env), Ok(Value::Integer(13)));
306 assert_eq!(eval("a%=8", env), Ok(Value::Integer(5)));
307 assert_eq!(env["a"], "5");
308 }
309
310 #[test]
311 fn combining_assignment_operators() {
312 let env = &mut HashMap::new();
313 assert_eq!(eval("a = b -= c = 7", env), Ok(Value::Integer(-7)));
314 assert_eq!(env["a"], "-7");
315 assert_eq!(env["b"], "-7");
316 assert_eq!(env["c"], "7");
317 }
318
319 #[test]
320 fn conditional_operator() {
321 let env = &mut HashMap::new();
322 assert_eq!(eval("1?a=10:(b=20)", env), Ok(Value::Integer(10)));
323 assert_eq!(env["a"], "10");
324 assert_eq!(env.get("b"), None);
325
326 assert_eq!(eval("0 ? x = 30 : (y = 40)", env), Ok(Value::Integer(40)));
327 assert_eq!(env.get("x"), None);
328 assert_eq!(env["y"], "40");
329
330 assert_eq!(eval("9 ? 1 : 0 ? 2 : 3", env), Ok(Value::Integer(1)));
331 assert_eq!(eval("0 ? 1 : 0 ? 2 : 3", env), Ok(Value::Integer(3)));
332 }
333
334 #[test]
335 fn conditional_evaluation_in_conditional_operators() {
336 let env = &mut HashMap::new();
337 assert_eq!(
338 eval("1 ? 2 : (a = 3) ? b = 4 : (c = 5)", env),
339 Ok(Value::Integer(2))
340 );
341 assert!(env.is_empty(), "expected empty env: {env:?}");
342
343 assert_eq!(
344 eval("0 ? (a = 1) ? b = 2 : (c = 3) : 4", env),
345 Ok(Value::Integer(4))
346 );
347 assert!(env.is_empty(), "expected empty env: {env:?}");
348 }
349
350 #[test]
351 fn boolean_logic_operators() {
352 let env = &mut HashMap::new();
353 assert_eq!(eval("0||0", env), Ok(Value::Integer(0)));
354 assert_eq!(eval(" 1 || 0 ", env), Ok(Value::Integer(1)));
355 assert_eq!(eval(" 0 || 1 ", env), Ok(Value::Integer(1)));
356 assert_eq!(eval("2 || 3", env), Ok(Value::Integer(1)));
357
358 assert_eq!(eval("0&&0", env), Ok(Value::Integer(0)));
359 assert_eq!(eval(" 1 && 0 ", env), Ok(Value::Integer(0)));
360 assert_eq!(eval(" 0 && 1 ", env), Ok(Value::Integer(0)));
361 assert_eq!(eval("2 && 3", env), Ok(Value::Integer(1)));
362 }
363
364 #[test]
365 fn conditional_evaluation_in_boolean_logic_operators() {
366 let env = &mut HashMap::new();
367 assert_eq!(eval("(a = 0) || (b = 2)", env), Ok(Value::Integer(1)));
368 assert_eq!(env["a"], "0");
369 assert_eq!(env["b"], "2");
370
371 let env = &mut HashMap::new();
372 assert_eq!(eval("(a = 3) || (b = 2)", env), Ok(Value::Integer(1)));
373 assert_eq!(env["a"], "3");
374 assert_eq!(env.get("b"), None);
375
376 let env = &mut HashMap::new();
377 assert_eq!(eval("(a = 0) && (b = 2)", env), Ok(Value::Integer(0)));
378 assert_eq!(env["a"], "0");
379 assert_eq!(env.get("b"), None);
380
381 let env = &mut HashMap::new();
382 assert_eq!(eval("(a = 3) && (b = 2)", env), Ok(Value::Integer(1)));
383 assert_eq!(env["a"], "3");
384 assert_eq!(env["b"], "2");
385
386 let env = &mut HashMap::new();
387 env.insert("x".to_string(), "@".to_string());
388 assert_eq!(eval("0 && (x || x)", env), Ok(Value::Integer(0)));
389 assert_eq!(eval("1 || x && x", env), Ok(Value::Integer(1)));
390
391 let env = &mut HashMap::new();
392 assert_eq!(eval("0 && ++x", env), Ok(Value::Integer(0)));
393 assert_eq!(env.get("x"), None);
394
395 let env = &mut HashMap::new();
396 assert_eq!(eval("0 && x++", env), Ok(Value::Integer(0)));
397 assert_eq!(env.get("x"), None);
398 }
399
400 #[test]
401 fn bitwise_logic_operators() {
402 let env = &mut HashMap::new();
403 assert_eq!(eval("3|5", env), Ok(Value::Integer(7)));
404 assert_eq!(eval(" 5 | 3 ", env), Ok(Value::Integer(7)));
405 assert_eq!(eval(" 10 | 10 ", env), Ok(Value::Integer(10)));
406 assert_eq!(eval(" 7 | 14 | 28 ", env), Ok(Value::Integer(31)));
407
408 assert_eq!(eval("3^5", env), Ok(Value::Integer(6)));
409 assert_eq!(eval(" 5 ^ 3 ", env), Ok(Value::Integer(6)));
410 assert_eq!(eval(" 10 ^ 10 ", env), Ok(Value::Integer(0)));
411 assert_eq!(eval(" 7 ^ 14 ^ 28 ", env), Ok(Value::Integer(21)));
412
413 assert_eq!(eval("3&5", env), Ok(Value::Integer(1)));
414 assert_eq!(eval(" 5 & 3 ", env), Ok(Value::Integer(1)));
415 assert_eq!(eval(" 10 & 10 ", env), Ok(Value::Integer(10)));
416 assert_eq!(eval(" 7 & 14 & 28 ", env), Ok(Value::Integer(4)));
417 }
418
419 #[test]
420 fn equality_comparison_operators() {
421 let env = &mut HashMap::new();
422 assert_eq!(eval("1==2", env), Ok(Value::Integer(0)));
423 assert_eq!(eval(" 2 == 1 ", env), Ok(Value::Integer(0)));
424 assert_eq!(eval(" 5 == 5 ", env), Ok(Value::Integer(1)));
425 assert_eq!(eval(" 1 == 2 == 2 ", env), Ok(Value::Integer(0)));
426
427 assert_eq!(eval("1!=2", env), Ok(Value::Integer(1)));
428 assert_eq!(eval(" 2 != 1 ", env), Ok(Value::Integer(1)));
429 assert_eq!(eval(" 5 != 5 ", env), Ok(Value::Integer(0)));
430 assert_eq!(eval(" 1 != 1 != 2 ", env), Ok(Value::Integer(1)));
431 }
432
433 #[test]
434 fn inequality_comparison_operators() {
435 let env = &mut HashMap::new();
436 assert_eq!(eval("1<2", env), Ok(Value::Integer(1)));
437 assert_eq!(eval(" 2 < 1 ", env), Ok(Value::Integer(0)));
438 assert_eq!(eval(" 5 < 5 ", env), Ok(Value::Integer(0)));
439 assert_eq!(eval(" 3 < 3 < 3 ", env), Ok(Value::Integer(1)));
440
441 assert_eq!(eval("1<=2", env), Ok(Value::Integer(1)));
442 assert_eq!(eval(" 2 <= 1 ", env), Ok(Value::Integer(0)));
443 assert_eq!(eval(" 5 <= 5 ", env), Ok(Value::Integer(1)));
444 assert_eq!(eval(" 3 <= 3 <= 3 ", env), Ok(Value::Integer(1)));
445
446 assert_eq!(eval("1>2", env), Ok(Value::Integer(0)));
447 assert_eq!(eval(" 2 > 1 ", env), Ok(Value::Integer(1)));
448 assert_eq!(eval(" 5 > 5 ", env), Ok(Value::Integer(0)));
449 assert_eq!(eval(" 3 > 3 > 3 ", env), Ok(Value::Integer(0)));
450
451 assert_eq!(eval("1>=2", env), Ok(Value::Integer(0)));
452 assert_eq!(eval(" 2 >= 1 ", env), Ok(Value::Integer(1)));
453 assert_eq!(eval(" 5 >= 5 ", env), Ok(Value::Integer(1)));
454 assert_eq!(eval(" 3 >= 3 >= 3 ", env), Ok(Value::Integer(0)));
455 }
456
457 #[test]
458 fn bit_shift_operators() {
459 let env = &mut HashMap::new();
460 assert_eq!(eval("5<<3", env), Ok(Value::Integer(40)));
461 assert_eq!(eval(" 3 << 5 ", env), Ok(Value::Integer(96)));
462 assert_eq!(eval(" 2 << 2 << 2 ", env), Ok(Value::Integer(32)));
463
464 assert_eq!(eval("64>>3", env), Ok(Value::Integer(8)));
465 assert_eq!(eval(" 63 >> 3 ", env), Ok(Value::Integer(7)));
466 assert_eq!(eval(" 2 >> 2 >> 2 ", env), Ok(Value::Integer(0)));
467 }
468
469 #[test]
470 fn overflow_in_bit_shifting() {
471 let env = &mut HashMap::new();
472 assert_eq!(
473 eval("0x4000000000000000<<1", env),
474 Err(Error {
475 cause: EvalError::Overflow.into(),
476 location: 18..20,
477 })
478 );
479 assert_eq!(
480 eval("0<<1000", env),
481 Err(Error {
482 cause: EvalError::Overflow.into(),
483 location: 1..3,
484 })
485 );
486 assert_eq!(
487 eval("0<<0x100000000", env),
488 Err(Error {
489 cause: EvalError::Overflow.into(),
490 location: 1..3,
491 })
492 );
493
494 assert_eq!(
495 eval("0>>1000", env),
496 Err(Error {
497 cause: EvalError::Overflow.into(),
498 location: 1..3,
499 })
500 );
501 assert_eq!(
502 eval("0>>0x100000000", env),
503 Err(Error {
504 cause: EvalError::Overflow.into(),
505 location: 1..3,
506 })
507 );
508 }
509
510 #[test]
511 fn bit_shifting_of_negative_values() {
512 let env = &mut HashMap::new();
513
514 assert_eq!(
516 eval("-1<<1", env),
517 Err(Error {
518 cause: EvalError::LeftShiftingNegative.into(),
519 location: 2..4,
520 })
521 );
522 assert_eq!(
523 eval("(-0x7FFFFFFFFFFFFFFF-1)<<1", env),
524 Err(Error {
525 cause: EvalError::LeftShiftingNegative.into(),
526 location: 23..25,
527 })
528 );
529
530 assert_eq!(eval("-4>>1", env), Ok(Value::Integer(-4 >> 1)));
532 assert_eq!(eval("-1>>1", env), Ok(Value::Integer(-1 >> 1)));
533 }
534
535 #[test]
536 fn reverse_bit_shifting() {
537 let env = &mut HashMap::new();
538 assert_eq!(
539 eval("1 << -1", env),
540 Err(Error {
541 cause: EvalError::ReverseShifting.into(),
542 location: 2..4,
543 })
544 );
545
546 assert_eq!(
547 eval("1 >> -1", env),
548 Err(Error {
549 cause: EvalError::ReverseShifting.into(),
550 location: 2..4,
551 })
552 );
553 }
554
555 #[test]
556 fn addition_operator() {
557 let env = &mut HashMap::new();
558 assert_eq!(eval("1+2", env), Ok(Value::Integer(3)));
559 assert_eq!(eval(" 12 + 34 ", env), Ok(Value::Integer(46)));
560 assert_eq!(eval(" 3 + 16 + 5 ", env), Ok(Value::Integer(24)));
561 }
562
563 #[test]
564 fn overflow_in_addition() {
565 let env = &mut HashMap::new();
566 assert_eq!(
567 eval("9223372036854775807+1", env),
568 Err(Error {
569 cause: EvalError::Overflow.into(),
570 location: 19..20,
571 })
572 );
573 }
574
575 #[test]
576 fn subtraction_operator() {
577 let env = &mut HashMap::new();
578 assert_eq!(eval("2-1", env), Ok(Value::Integer(1)));
579 assert_eq!(eval(" 42 - 15 ", env), Ok(Value::Integer(27)));
580 assert_eq!(eval(" 10 - 7 - 5 ", env), Ok(Value::Integer(-2)));
581 }
582
583 #[test]
584 fn overflow_in_subtraction() {
585 let env = &mut HashMap::new();
586 assert_eq!(
587 eval("0-9223372036854775807-2", env),
588 Err(Error {
589 cause: EvalError::Overflow.into(),
590 location: 21..22,
591 })
592 );
593 }
594
595 #[test]
596 fn multiplication_operator() {
597 let env = &mut HashMap::new();
598 assert_eq!(eval("3*6", env), Ok(Value::Integer(18)));
599 assert_eq!(eval(" 5 * 11 ", env), Ok(Value::Integer(55)));
600 assert_eq!(eval(" 2 * 3 * 4 ", env), Ok(Value::Integer(24)));
601 }
602
603 #[test]
604 fn overflow_in_multiplication() {
605 let env = &mut HashMap::new();
606 assert_eq!(
607 eval("0x100000000 * 0x80000000", env),
608 Err(Error {
609 cause: EvalError::Overflow.into(),
610 location: 12..13,
611 })
612 );
613 }
614
615 #[test]
616 fn division_operator() {
617 let env = &mut HashMap::new();
618 assert_eq!(eval("6/2", env), Ok(Value::Integer(3)));
619 assert_eq!(eval(" 120 / 24 ", env), Ok(Value::Integer(5)));
620 assert_eq!(eval(" 120/10/5 ", env), Ok(Value::Integer(2)));
621 }
622
623 #[test]
624 fn division_by_zero() {
625 let env = &mut HashMap::new();
626 assert_eq!(
627 eval("1/0", env),
628 Err(Error {
629 cause: EvalError::DivisionByZero.into(),
630 location: 1..2,
631 })
632 );
633 assert_eq!(
634 eval("0/0", env),
635 Err(Error {
636 cause: EvalError::DivisionByZero.into(),
637 location: 1..2,
638 })
639 );
640 assert_eq!(
641 eval("10/0", env),
642 Err(Error {
643 cause: EvalError::DivisionByZero.into(),
644 location: 2..3,
645 })
646 );
647 }
648
649 #[test]
650 fn overflow_in_division() {
651 let env = &mut HashMap::new();
652 assert_eq!(
653 eval("(-0x7FFFFFFFFFFFFFFF-1)/-1", env),
654 Err(Error {
655 cause: EvalError::Overflow.into(),
656 location: 23..24,
657 })
658 );
659 }
660
661 #[test]
662 fn remainder_operator() {
663 let env = &mut HashMap::new();
664 assert_eq!(eval("6%2", env), Ok(Value::Integer(0)));
665 assert_eq!(eval(" 17 % 5 ", env), Ok(Value::Integer(2)));
666 assert_eq!(eval(" 42 % 11 % 5 ", env), Ok(Value::Integer(4)));
667 }
668
669 #[test]
670 fn remainder_by_zero() {
671 let env = &mut HashMap::new();
672 assert_eq!(
673 eval("1%0", env),
674 Err(Error {
675 cause: EvalError::DivisionByZero.into(),
676 location: 1..2,
677 })
678 );
679 assert_eq!(
680 eval("0%0", env),
681 Err(Error {
682 cause: EvalError::DivisionByZero.into(),
683 location: 1..2,
684 })
685 );
686 assert_eq!(
687 eval("10%0", env),
688 Err(Error {
689 cause: EvalError::DivisionByZero.into(),
690 location: 2..3,
691 })
692 );
693 }
694
695 #[test]
696 fn overflow_in_remainder() {
697 let env = &mut HashMap::new();
698 assert_eq!(
699 eval("(-0x7FFFFFFFFFFFFFFF-1)%-1", env),
700 Err(Error {
701 cause: EvalError::Overflow.into(),
702 location: 23..24,
703 })
704 );
705 }
706
707 #[test]
708 fn plus_prefix_operator() {
709 let env = &mut HashMap::new();
710 assert_eq!(eval("+0", env), Ok(Value::Integer(0)));
711 assert_eq!(eval(" + 10 ", env), Ok(Value::Integer(10)));
712 assert_eq!(eval(" + + 57", env), Ok(Value::Integer(57)));
713 }
714
715 #[test]
716 fn numeric_negation_operator() {
717 let env = &mut HashMap::new();
718 assert_eq!(eval("-0", env), Ok(Value::Integer(0)));
719 assert_eq!(eval(" - 12 ", env), Ok(Value::Integer(-12)));
720 assert_eq!(eval(" - - 49", env), Ok(Value::Integer(49)));
721 assert_eq!(eval(" - - - 49", env), Ok(Value::Integer(-49)));
722 }
723
724 #[test]
725 fn overflow_in_numeric_negation() {
726 let env = &mut HashMap::new();
727 assert_eq!(
728 eval("-0x7FFFFFFFFFFFFFFF-1", env),
729 Ok(Value::Integer(i64::MIN))
730 );
731 assert_eq!(
732 eval(" - (-0x7FFFFFFFFFFFFFFF-1)", env),
733 Err(Error {
734 cause: EvalError::Overflow.into(),
735 location: 1..2
736 })
737 );
738 }
739
740 #[test]
741 fn bitwise_negation_operator() {
742 let env = &mut HashMap::new();
743 assert_eq!(eval("~0", env), Ok(Value::Integer(-1)));
744 assert_eq!(eval(" ~ 3 ", env), Ok(Value::Integer(!3)));
745 assert_eq!(eval(" ~ ~ 42", env), Ok(Value::Integer(42)));
746 assert_eq!(eval(" ~ ~ ~ 0x38E7", env), Ok(Value::Integer(!0x38E7)));
747 }
748
749 #[test]
750 fn logical_negation_operator() {
751 let env = &mut HashMap::new();
752 assert_eq!(eval("!0", env), Ok(Value::Integer(1)));
753 assert_eq!(eval(" ! 1 ", env), Ok(Value::Integer(0)));
754 assert_eq!(eval(" ! 2 ", env), Ok(Value::Integer(0)));
755 assert_eq!(eval(" ! ! 3", env), Ok(Value::Integer(1)));
756 }
757
758 #[test]
759 fn prefix_increment_operator() {
760 let env = &mut HashMap::new();
761 assert_eq!(eval("++a", env), Ok(Value::Integer(1)));
762 assert_eq!(eval("++a", env), Ok(Value::Integer(2)));
763 assert_eq!(eval("++a", env), Ok(Value::Integer(3)));
764 assert_eq!(eval("a", env), Ok(Value::Integer(3)));
765 }
766
767 #[test]
768 fn prefix_incrementing_non_variable() {
769 let env = &mut HashMap::new();
770 assert_eq!(
771 eval(" ++ +a ", env),
772 Err(Error {
773 cause: EvalError::AssignmentToValue.into(),
774 location: 1..3,
775 })
776 );
777 }
778
779 #[test]
780 fn overflow_in_increment() {
781 let env = &mut HashMap::new();
782 env.insert("i".to_string(), "9223372036854775807".to_string());
783 assert_eq!(
784 eval(" ++ i", env),
785 Err(Error {
786 cause: EvalError::Overflow.into(),
787 location: 2..4,
788 })
789 );
790 }
791
792 #[test]
793 fn prefix_decrement_operator() {
794 let env = &mut HashMap::new();
795 assert_eq!(eval("--d", env), Ok(Value::Integer(-1)));
796 assert_eq!(eval("--d", env), Ok(Value::Integer(-2)));
797 assert_eq!(eval("--d", env), Ok(Value::Integer(-3)));
798 assert_eq!(eval("d", env), Ok(Value::Integer(-3)));
799 }
800
801 #[test]
802 fn overflow_in_decrement() {
803 let env = &mut HashMap::new();
804 env.insert("i".to_string(), "-9223372036854775808".to_string());
805 assert_eq!(
806 eval(" -- i", env),
807 Err(Error {
808 cause: EvalError::Overflow.into(),
809 location: 1..3,
810 })
811 );
812 }
813
814 #[test]
815 fn prefix_decrementing_non_variable() {
816 let env = &mut HashMap::new();
817 assert_eq!(
818 eval(" -- +a ", env),
819 Err(Error {
820 cause: EvalError::AssignmentToValue.into(),
821 location: 2..4,
822 })
823 );
824 }
825
826 #[test]
827 fn postfix_increment_operator() {
828 let env = &mut HashMap::new();
829 assert_eq!(eval("a++", env), Ok(Value::Integer(0)));
830 assert_eq!(eval("a++", env), Ok(Value::Integer(1)));
831 assert_eq!(eval("a++", env), Ok(Value::Integer(2)));
832 assert_eq!(eval("a", env), Ok(Value::Integer(3)));
833 }
834
835 #[test]
836 fn postfix_incrementing_non_variable() {
837 let env = &mut HashMap::new();
838 assert_eq!(
839 eval("5++", env),
840 Err(Error {
841 cause: EvalError::AssignmentToValue.into(),
842 location: 1..3,
843 })
844 );
845 }
846
847 #[test]
848 fn postfix_decrement_operator() {
849 let env = &mut HashMap::new();
850 assert_eq!(eval("a--", env), Ok(Value::Integer(0)));
851 assert_eq!(eval("a--", env), Ok(Value::Integer(-1)));
852 assert_eq!(eval("a--", env), Ok(Value::Integer(-2)));
853 assert_eq!(eval("a", env), Ok(Value::Integer(-3)));
854 }
855
856 #[test]
857 fn postfix_decrementing_non_variable() {
858 let env = &mut HashMap::new();
859 assert_eq!(
860 eval("7 --", env),
861 Err(Error {
862 cause: EvalError::AssignmentToValue.into(),
863 location: 2..4,
864 })
865 );
866 }
867
868 #[test]
869 fn combining_operators_of_same_precedence() {
870 let env = &mut HashMap::new();
871 assert_eq!(eval("2+5-3", env), Ok(Value::Integer(4)));
872 }
873
874 #[test]
875 fn combining_operators_of_different_precedences() {
876 let env = &mut HashMap::new();
877 assert_eq!(eval("2+3*4", env), Ok(Value::Integer(14)));
878 assert_eq!(eval("2*3+4", env), Ok(Value::Integer(10)));
879 }
880
881 #[test]
882 fn combining_prefix_and_postfix_operators() {
883 let env = &mut HashMap::new();
884 assert_eq!(eval("+a++", env), Ok(Value::Integer(0)));
885 assert_eq!(eval("-a++", env), Ok(Value::Integer(-1)));
886 assert_eq!(eval("~a--", env), Ok(Value::Integer(-3)));
887 assert_eq!(eval("!a--", env), Ok(Value::Integer(0)));
888 }
889
890 #[test]
891 fn parentheses() {
892 let env = &mut HashMap::new();
893 assert_eq!(eval("(42)", env), Ok(Value::Integer(42)));
894 assert_eq!(eval("(1+2)", env), Ok(Value::Integer(3)));
895 assert_eq!(eval("(2+3)*4", env), Ok(Value::Integer(20)));
896 assert_eq!(eval("2*(3+4)", env), Ok(Value::Integer(14)));
897 assert_eq!(eval(" ( 6 - ( 7 - 3 ) ) * 2 ", env), Ok(Value::Integer(4)));
898 assert_eq!(eval(" 4 | ( ( 2 && 2 ) & 3 )", env), Ok(Value::Integer(5)));
899 }
900
901 #[test]
902 fn combining_postfix_operator_and_parentheses() {
903 let env = &mut HashMap::new();
904 assert_eq!(eval("(a)++", env), Ok(Value::Integer(0)));
905 assert_eq!(eval("(a) --", env), Ok(Value::Integer(1)));
906 assert_eq!(eval("a", env), Ok(Value::Integer(0)));
907 }
908
909 #[test]
910 fn unmatched_parenthesis() {
911 let env = &mut HashMap::new();
912 assert_eq!(
913 eval(" ( 1 ", env),
914 Err(Error {
915 cause: ErrorCause::SyntaxError(SyntaxError::UnclosedParenthesis {
916 opening_location: 1..2,
917 }),
918 location: 5..5,
919 })
920 );
921 }
922}