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