import Mathlib.Data.Finset.Basic

/-!

Base language.

This file defines the core object language for the program analysis and
transformation. It's a very basic imperative language. The `Spa/Language/Tagged/Basic.lean`
file provides an auto-derived version of the `Expr`, `BasicStmt`, and `Stmt` data
types with unique IDs per condtructor, enabling in-AST pointers.

-/

namespace Spa

/-- A value-producing expression. Currently, this cannot have side effects. -/
inductive Expr where
  | add (e₁ e₂ : Expr)
  | sub (e₁ e₂ : Expr)
  | var (x : String)
  | num (n : ℕ)
  deriving DecidableEq

/-- A statement that cannot alter control flow (and thus, can be part of a basic block).

    This differs from, e.g., a loop, which can cause execution to jump to its top several times. -/
inductive BasicStmt where
  | assign (x : String) (e : Expr)
  | noop
  deriving DecidableEq

/-- Any statements, which may or may not change program state (variable assignments). -/
inductive Stmt where
  | basic (bs : BasicStmt)
  | andThen (s₁ s₂ : Stmt)
  | ifElse (e : Expr) (s₁ s₂ : Stmt)
  | whileLoop (e : Expr) (s : Stmt)
  deriving DecidableEq

/-- Variables mentioned in this expression. -/
def Expr.vars : Expr → Finset String
  | .add l r => l.vars ∪ r.vars
  | .sub l r => l.vars ∪ r.vars
  | .var s => {s}
  | .num _ => ∅

/-- Variables assigned or mentioned in this basic statement. -/
def BasicStmt.vars : BasicStmt → Finset String
  | .assign x e => {x} ∪ e.vars
  | .noop => ∅

/-- Variables assigned or mentioned in this statement. -/
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
