import Mathlib.Data.Finset.Basic

namespace Spa

inductive Expr where
  | add (e₁ e₂ : Expr)
  | sub (e₁ e₂ : Expr)
  | var (x : String)
  | num (n : ℕ)
  deriving DecidableEq

inductive BasicStmt where
  | assign (x : String) (e : Expr)
  | noop
  deriving DecidableEq

inductive Stmt where
  | basic (bs : BasicStmt)
  | andThen (s₁ s₂ : Stmt)
  | ifElse (e : Expr) (s₁ s₂ : Stmt)
  | whileLoop (e : Expr) (s : Stmt)
  deriving DecidableEq

def Expr.vars : Expr → Finset String
  | .add l r => l.vars ∪ r.vars
  | .sub l r => l.vars ∪ r.vars
  | .var s => {s}
  | .num _ => ∅

def BasicStmt.vars : BasicStmt → Finset String
  | .assign x e => {x} ∪ e.vars
  | .noop => ∅

def Stmt.vars : Stmt → Finset String
  | .basic bs => bs.vars
  | .andThen s₁ s₂ => s₁.vars ∪ s₂.vars
  | .ifElse e s₁ s₂ => (e.vars ∪ s₁.vars) ∪ s₂.vars
  | .whileLoop e s => e.vars ∪ s.vars

end Spa
