100 lines
4.6 KiB
Lean4
100 lines
4.6 KiB
Lean4
import Spa.Language.Base
|
||
import Spa.Lattice
|
||
import Spa.Interp
|
||
|
||
/-!
|
||
|
||
# Operational Semantics
|
||
|
||
This file contains the operational semantics for the object language defined in
|
||
`Spa.Language.Base`. Right now, all values in the language are integers.
|
||
The semantics are big-step, and lead to a fully constructed proof tree
|
||
containing the derivation connecting the initial and final states.
|
||
All pretty standard.
|
||
|
||
-/
|
||
|
||
namespace Spa
|
||
|
||
/-- A value in the object language. Currently, the only possible case is
|
||
an integer. -/
|
||
inductive Value where
|
||
| int (z : ℤ)
|
||
deriving DecidableEq
|
||
|
||
/-- An environment mapping variables to their values. -/
|
||
def Env : Type := List (String × Value)
|
||
|
||
inductive Env.Mem : String × Value → Env → Prop
|
||
| here (s : String) (v : Value) (ρ : Env) : Env.Mem (s, v) ((s, v) :: ρ)
|
||
| there (s s' : String) (v v' : Value) (ρ : Env) :
|
||
¬(s = s') → Env.Mem (s, v) ρ → Env.Mem (s, v) ((s', v') :: ρ)
|
||
|
||
/-- Inference rules for evaluating an expression (`Spa.Expr`) in a given
|
||
environment. Pretty standard big-step expression evaluation. -/
|
||
inductive EvalExpr : Env → Expr → Value → Prop
|
||
| num (ρ : Env) (n : ℕ) : EvalExpr ρ (.num n) (.int n)
|
||
| var (ρ : Env) (x : String) (v : Value) :
|
||
Env.Mem (x, v) ρ → EvalExpr ρ (.var x) v
|
||
| add (ρ : Env) (e₁ e₂ : Expr) (z₁ z₂ : ℤ) :
|
||
EvalExpr ρ e₁ (.int z₁) → EvalExpr ρ e₂ (.int z₂) →
|
||
EvalExpr ρ (.add e₁ e₂) (.int (z₁ + z₂))
|
||
| sub (ρ : Env) (e₁ e₂ : Expr) (z₁ z₂ : ℤ) :
|
||
EvalExpr ρ e₁ (.int z₁) → EvalExpr ρ e₂ (.int z₂) →
|
||
EvalExpr ρ (.sub e₁ e₂) (.int (z₁ - z₂))
|
||
|
||
/-- Inference rules for evaluating a basic statement (`Spa.BasicStmt`) in
|
||
a given environment, potentially changing the environment.
|
||
Pretty standard big-step evaluation. -/
|
||
inductive EvalBasicStmt : Env → BasicStmt → Env → Prop
|
||
| noop (ρ : Env) : EvalBasicStmt ρ .noop ρ
|
||
| assign (ρ : Env) (x : String) (e : Expr) (v : Value) :
|
||
EvalExpr ρ e v → EvalBasicStmt ρ (.assign x e) ((x, v) :: ρ)
|
||
|
||
/-- Inference rules for evaluating a sequence of basic statements. -/
|
||
inductive EvalBasicStmts : Env → List BasicStmt → Env → Prop
|
||
| nil {ρ : Env} : EvalBasicStmts ρ [] ρ
|
||
| cons {ρ₁ ρ₂ ρ₃ : Env} {bs : BasicStmt} {bss : List BasicStmt} :
|
||
EvalBasicStmt ρ₁ bs ρ₂ → EvalBasicStmts ρ₂ bss ρ₃ →
|
||
EvalBasicStmts ρ₁ (bs :: bss) ρ₃
|
||
|
||
/-- Inference rules for evaluating statements (`Spa.Stmt`) in a given
|
||
environment, potentially changing the environment.
|
||
Pretty standard big-step evaluation. -/
|
||
inductive EvalStmt : Env → Stmt → Env → Prop
|
||
| basic (ρ₁ ρ₂ : Env) (bs : BasicStmt) :
|
||
EvalBasicStmt ρ₁ bs ρ₂ → EvalStmt ρ₁ (.basic bs) ρ₂
|
||
| andThen (ρ₁ ρ₂ ρ₃ : Env) (s₁ s₂ : Stmt) :
|
||
EvalStmt ρ₁ s₁ ρ₂ → EvalStmt ρ₂ s₂ ρ₃ →
|
||
EvalStmt ρ₁ (.andThen s₁ s₂) ρ₃
|
||
| ifTrue (ρ₁ ρ₂ : Env) (e : Expr) (z : ℤ) (s₁ s₂ : Stmt) :
|
||
EvalExpr ρ₁ e (.int z) → ¬(z = 0) → EvalStmt ρ₁ s₁ ρ₂ →
|
||
EvalStmt ρ₁ (.ifElse e s₁ s₂) ρ₂
|
||
| ifFalse (ρ₁ ρ₂ : Env) (e : Expr) (s₁ s₂ : Stmt) :
|
||
EvalExpr ρ₁ e (.int 0) → EvalStmt ρ₁ s₂ ρ₂ →
|
||
EvalStmt ρ₁ (.ifElse e s₁ s₂) ρ₂
|
||
| whileTrue (ρ₁ ρ₂ ρ₃ : Env) (e : Expr) (z : ℤ) (s : Stmt) :
|
||
EvalExpr ρ₁ e (.int z) → ¬(z = 0) → EvalStmt ρ₁ s ρ₂ →
|
||
EvalStmt ρ₂ (.whileLoop e s) ρ₃ →
|
||
EvalStmt ρ₁ (.whileLoop e s) ρ₃
|
||
| whileFalse (ρ : Env) (e : Expr) (s : Stmt) :
|
||
EvalExpr ρ e (.int 0) →
|
||
EvalStmt ρ (.whileLoop e s) ρ
|
||
|
||
/-- For the purpose of static analysis, lattices we define describe program
|
||
state, or better yet, they describe _values_ in the program.
|
||
This class should be provided by each analysis' lattice (see also `Spa/Analysis/Forward.lean`)
|
||
to describe what each lattice value means in terms of the language.
|
||
|
||
In addition to providing the interpretation (`Spa.Interp`), the lattice
|
||
combinators `⊔` and `⊓` must respect disjunction and conjunction respectively.
|
||
This is because possible paths through a control flow graph (`Spa/Language/Graphs.lean`),
|
||
are tied to lattice operations used by the analysis engine. -/
|
||
class LatticeInterpretation (L : Type*) [Lattice L] extends Interp L (Value → Prop) where
|
||
interp_sup : ∀ {l₁ l₂ : L} (v : Value),
|
||
interp l₁ v ∨ interp l₂ v → interp (l₁ ⊔ l₂) v
|
||
interp_inf : ∀ {l₁ l₂ : L} (v : Value),
|
||
interp l₁ v ∧ interp l₂ v → interp (l₁ ⊓ l₂) v
|
||
|
||
end Spa
|