Theory VIMP_Regression

theory VIMP_Regression
  imports "Voblint_VIMP.VIMP_Notation"
begin

section ‹VIMP syntax and semantics regressions›

text ‹Build-checked regression assertions on concrete VIMP snippets and values, moved out of
  ‹VIMP_Notation› and ‹VIMP_Expr›.  Nothing cites them; the build failing is the signal.›

subsection ‹Concrete syntax and precedence›

text ‹Each snippet elaborates to a fixed ‹com› term or to its fully parenthesised form: dangling
  and chained ‹else›, statement boundaries, calls and returns, and C operator precedence.›

lemma notation_if_without_else:
  "imp ⟦ if (x < 0) { x = -x; } ⟧ =
    If () (Less (V (STR ''x'')) (N 0))
      (Assign () (STR ''x'') (Minus (N 0) (V (STR ''x'')))) (SKIP ())"
  by simp

lemma notation_else_if_chain:
  "imp ⟦
     if (x < 0) { y = -1; }
     else if (x == 0) { y = 0; }
     else if (x < 10) { y = 1; }
   ⟧ =
   imp ⟦
     if (x < 0) { y = -1; } else {
       if (x == 0) { y = 0; } else {
         if (x < 10) { y = 1; } else { skip; }
       }
     }
   ⟧"
  by simp

lemma notation_else_if_final_else:
  "imp ⟦ if (x) { } else if (y) { skip; } else { x = 1; } ⟧ =
    If () (V (STR ''x'')) (SKIP ())
      (If () (V (STR ''y'')) (SKIP ()) (Assign () (STR ''x'') (N 1)))"
  by simp

lemma notation_block_statement_boundaries:
  "imp ⟦ x = 0; while (x < 2) { x = x + 1; } if (x) { } ⟧ =
    Seq (Seq (Assign () (STR ''x'') (N 0))
      (While () (Less (V (STR ''x'')) (N 2))
        (Assign () (STR ''x'') (Plus (V (STR ''x'')) (N 1)))))
      (If () (V (STR ''x'')) (SKIP ()) (SKIP ()))"
  by simp

lemma notation_fun_call_return:
  "prog_main (program {
      fun id(x) { return x; }
      fun ping() { return; }
      fun main() { x = id(1); ping(); }
    }) =
    Seq (Call () (Some (STR ''x'')) (STR ''id'') [N 1])
      (Call () None (STR ''ping'') [])"
  by simp

lemma notation_comparison_less:
  "imp ⟦ __voblint_check(x < y); ⟧ =
    Check () (0, 0) (Less (V (STR ''x'')) (V (STR ''y'')))"
  by simp

lemma notation_comparison_less_eq:
  "imp ⟦ __voblint_check(x <= y); ⟧ =
    Check () (0, 0) (LessEq (V (STR ''x'')) (V (STR ''y'')))"
  by simp

lemma notation_comparison_greater:
  "imp ⟦ __voblint_check(x > y); ⟧ =
    Check () (0, 0) (Greater (V (STR ''x'')) (V (STR ''y'')))"
  by simp

lemma notation_comparison_greater_eq:
  "imp ⟦ __voblint_check(x >= y); ⟧ =
    Check () (0, 0) (GreaterEq (V (STR ''x'')) (V (STR ''y'')))"
  by simp

lemma notation_comparison_eq:
  "imp ⟦ __voblint_check(x == y); ⟧ =
    Check () (0, 0) (Eq (V (STR ''x'')) (V (STR ''y'')))"
  by simp

lemma notation_comparison_not_eq:
  "imp ⟦ __voblint_check(x != y); ⟧ =
    Check () (0, 0) (NotEq (V (STR ''x'')) (V (STR ''y'')))"
  by simp

lemma notation_comparison_precedence:
  "imp ⟦ __voblint_check(x + 1 <= y * 2 && x != y); ⟧ =
    Check () (0, 0) (And
      (LessEq (Plus (V (STR ''x'')) (N 1)) (Times (V (STR ''y'')) (N 2)))
      (NotEq (V (STR ''x'')) (V (STR ''y''))))"
  by simp

lemma notation_relational_before_equality:
  "imp ⟦ __voblint_check(x == y < z); ⟧ =
    imp ⟦ __voblint_check(x == (y < z)); ⟧"
  "imp ⟦ __voblint_check(x < y != z); ⟧ =
    imp ⟦ __voblint_check((x < y) != z); ⟧"
  "imp ⟦ __voblint_check(x + 1 >= y == z <= w * 2); ⟧ =
    imp ⟦ __voblint_check((x + 1 >= y) == (z <= w * 2)); ⟧"
  by simp_all

lemma notation_division_remainder:
  "imp ⟦ x = a / b; y = a % b; ⟧ =
    Seq (Assign () (STR ''x'') (Div (V (STR ''a'')) (V (STR ''b''))))
      (Assign () (STR ''y'') (Mod (V (STR ''a'')) (V (STR ''b''))))"
  by simp

lemma notation_multiplicative_precedence:
  "imp ⟦ x = 20 / 3 % 4 * 2 + 1; ⟧ =
    imp ⟦ x = (((20 / 3) % 4) * 2) + 1; ⟧"
  "imp ⟦ x = -7 / 3; ⟧ = Assign () (STR ''x'') (Div (N (-7)) (N 3))"
  "imp ⟦ __voblint_check(1 == 20 / 3 % 4 < 3); ⟧ =
    imp ⟦ __voblint_check(1 == (((20 / 3) % 4) < 3)); ⟧"
  by simp_all

subsection ‹Comparison semantics›

text ‹Comparisons yield ‹1› or ‹0› on signed operands, including the boundaries at ‹-1› and ‹0›.›

lemma comparison_signed_boundaries:
  "map (λe. ⟦e⟧e s)
    [Less (N (-1)) (N 0), LessEq (N (-1)) (N (-1)),
     Greater (N 0) (N (-1)), GreaterEq (N (-1)) (N (-1)),
     Eq (N (-1)) (N (-1)), NotEq (N (-1)) (N 0)] = [1, 1, 1, 1, 1, 1]"
  "map (λe. ⟦e⟧e s)
    [Less (N (-1)) (N (-1)), LessEq (N 0) (N (-1)),
     Greater (N (-1)) (N (-1)), GreaterEq (N (-1)) (N 0),
     Eq (N (-1)) (N 0), NotEq (N (-1)) (N (-1))] = [0, 0, 0, 0, 0, 0]"
  by simp_all

subsection ‹Division and remainder›

text ‹‹c_div› truncates toward zero and ‹c_mod› takes the dividend's sign, for all four sign
  combinations; a zero divisor yields ‹0› for division and the dividend for remainder.›

lemma c_div_signed_examples:
  "map (λ(a, b). c_div a b) [(7, 3), (-7, 3), (7, -3), (-7, -3)] =
    [2, -2, -2, 2]"
  by (simp add: c_div_def)

lemma c_mod_signed_examples:
  "map (λ(a, b). c_mod a b) [(7, 3), (-7, 3), (7, -3), (-7, -3)] =
    [1, -1, 1, -1]"
  by (simp add: c_mod_def c_div_def)

lemma aval_division_remainder:
  "map (λe. ⟦e⟧e s)
    [Div (N 7) (N 3), Div (N (-7)) (N 3),
     Div (N 7) (N (-3)), Div (N (-7)) (N (-3)),
     Mod (N 7) (N 3), Mod (N (-7)) (N 3),
     Mod (N 7) (N (-3)), Mod (N (-7)) (N (-3)),
     Div (N 7) (N 0), Mod (N (-7)) (N 0)] = [2, -2, -2, 2, 1, -1, 1, -1, 0, -7]"
  by (simp add: c_div_def c_mod_def)

end