import Spa.Analysis.Forward.Evaluation

namespace Spa

namespace Forward

variable {L : Type} [Lattice L] {prog : Program} [E : ExprEvaluator L prog]

def updateVariablesFromExpression (k : String) (e : Expr)
    (vs : VariableValues L prog) : VariableValues L prog :=
  FiniteMap.generalizedUpdate id (fun _ vs => E.eval e vs) [k] vs

lemma updateVariablesFromExpression_mono (k : String) (e : Expr) :
    Monotone (updateVariablesFromExpression (L := L) (prog := prog) k e) :=
  FiniteMap.generalizedUpdate_monotone monotone_id (fun _ => E.eval_mono e)

def evalBasicStmt (_ : prog.State) (bs : BasicStmt)
    (vs : VariableValues L prog) : VariableValues L prog :=
  match bs with
  | .assign k e => updateVariablesFromExpression k e vs
  | .noop => vs

lemma evalBasicStmt_mono (s : prog.State) (bs : BasicStmt) :
    Monotone (evalBasicStmt (L := L) (prog := prog) s bs) := by
  cases bs with
  | assign k e => exact updateVariablesFromExpression_mono k e
  | noop => exact monotone_id

instance ExprEvaluator.toStmtEvaluator : StmtEvaluator L prog :=
  ⟨evalBasicStmt, evalBasicStmt_mono⟩

instance ExprEvaluator.toStmtEvaluator_valid [LatticeInterpretation L]
    [ValidExprEvaluator L prog] : ValidStmtEvaluator L prog := by
  constructor
  intro s vs ρ₁ ρ₂ bs hbs hvs
  cases hbs with
  | noop => exact hvs
  | assign k e v hev =>
    intro k' l hk'l v' hv'
    cases hv' with
    | here =>
      have hk'l₀ : (k, l) ∈ FiniteMap.generalizedUpdate (ks := prog.vars) id
          (fun _ vs => E.eval e vs) [k] vs := hk'l
      have hl := FiniteMap.generalizedUpdate_mem_eq (f := id)
        (g := fun _ vs => E.eval e vs) (List.mem_singleton_self k) hk'l₀
      rw [hl]
      exact ValidExprEvaluator.valid hev hvs
    | there _ _ _ _ _ hne hmem' =>
      have hk'l₀ : (k', l) ∈ FiniteMap.generalizedUpdate (ks := prog.vars) id
          (fun _ vs => E.eval e vs) [k] vs := hk'l
      have hk'l' : (k', l) ∈ (id vs : VariableValues L prog) :=
        FiniteMap.generalizedUpdate_not_mem_backward
          (fun hmem => hne (List.mem_singleton.mp hmem)) hk'l₀
      exact hvs _ _ hk'l' _ hmem'

end Forward

end Spa
