use crate::ast::{BinOp, VerifyBlock, VerifyLaw};
use crate::codegen::CodegenContext;
use super::super::super::expr::aver_name_to_lean;
use super::super::AutoProof;
pub(in super::super) fn emit_wrapper_over_recursion_law(
vb: &VerifyBlock,
law: &VerifyLaw,
_ctx: &CodegenContext,
wrapper_fn: &str,
inner_fn: &str,
other_fn: &str,
combine_op: BinOp,
) -> Option<AutoProof> {
let op = match combine_op {
BinOp::Add => "+",
BinOp::Mul => "*",
BinOp::Sub => "-",
_ => return None,
};
let neutral = match combine_op {
BinOp::Mul => "1",
_ => "0",
};
let wrapper_l = aver_name_to_lean(wrapper_fn);
let inner_l = aver_name_to_lean(inner_fn);
let other_l = aver_name_to_lean(other_fn);
let acc_thm = format!("{inner_l}_acc");
let support_lines = vec![
format!(
"theorem {acc_thm} (xs : List Int) (a : Int) : {inner_l} xs a = a {op} {inner_l} xs {neutral} := by"
),
" induction xs generalizing a with".to_string(),
format!(" | nil => simp [{inner_l}]"),
format!(
" | cons h t ih => simp only [{inner_l}]; rw [ih (a {op} h), ih ({neutral} {op} h)]; omega"
),
];
let proof_lines = vec![
" intro xs".to_string(),
" induction xs with".to_string(),
format!(" | nil => simp [{wrapper_l}, {inner_l}, {other_l}]"),
" | cons h t ih =>".to_string(),
format!(" simp only [{wrapper_l}, {inner_l}, {other_l}]"),
format!(" rw [{acc_thm} t ({neutral} {op} h)]"),
format!(" simp only [{wrapper_l}] at ih"),
" omega".to_string(),
];
let _ = (vb, law);
Some(AutoProof {
support_lines,
proof_lines,
replaces_theorem: false,
})
}