blob: 0f9f170794a2d35586a062aacd847edb5d4e0cfe [file]
/-
Copyright (c) 2022 Henrik Böving. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Henrik Böving
-/
import Lean.Expr
import Lean.Compiler.LCNF.Basic
import Lean.Compiler.LCNF.CompilerM
namespace Lean.Compiler.LCNF
class TraverseFVar (α : Type) where
mapFVarM {m : Type → Type} [MonadLiftT CompilerM m] [Monad m] (f : FVarId → m FVarId) (val : α) : m α
forFVarM {m : Type → Type} [Monad m] (f : FVarId → m Unit) (val : α) : m Unit
export TraverseFVar (mapFVarM forFVarM)
partial def Expr.mapFVarM [MonadLiftT CompilerM m] [Monad m] (f : FVarId → m FVarId) (e : Expr) : m Expr := do
match e with
| .app fn arg => return e.updateApp! (← mapFVarM f fn) (← mapFVarM f arg)
| .fvar fvarId => return e.updateFVar! (← f fvarId)
| .lam _ ty body _ => return e.updateLambdaE! (← mapFVarM f ty) (← mapFVarM f body)
| .forallE _ ty body _ => return e.updateForallE! (← mapFVarM f ty) (← mapFVarM f body)
| .bvar .. | .sort .. => return e
| .mdata .. | .const .. | .lit .. => return e
| .letE .. | .proj .. | .mvar .. => unreachable! -- LCNF types do not have this kind of expr
partial def Expr.forFVarM [Monad m] (f : FVarId → m Unit) (e : Expr) : m Unit := do
match e with
| .app fn arg =>
forFVarM f fn
forFVarM f arg
| .fvar fvarId => f fvarId
| .lam _ ty body .. =>
forFVarM f ty
forFVarM f body
| .forallE _ ty body .. =>
forFVarM f ty
forFVarM f body
| .bvar .. | .sort .. => return
| .mdata .. | .const .. | .lit .. => return
| .mvar .. | .letE .. | .proj .. => unreachable! -- LCNF types do not have this kind of expr
instance : TraverseFVar Expr where
mapFVarM := Expr.mapFVarM
forFVarM := Expr.forFVarM
def Arg.mapFVarM [MonadLiftT CompilerM m] [Monad m] (f : FVarId → m FVarId) (arg : Arg) : m Arg := do
match arg with
| .erased => return .erased
| .type e => return arg.updateType! (← TraverseFVar.mapFVarM f e)
| .fvar fvarId => return arg.updateFVar! (← f fvarId)
def Arg.forFVarM [Monad m] (f : FVarId → m Unit) (arg : Arg) : m Unit := do
match arg with
| .erased => return ()
| .type e => TraverseFVar.forFVarM f e
| .fvar fvarId => f fvarId
instance : TraverseFVar Arg where
mapFVarM := Arg.mapFVarM
forFVarM := Arg.forFVarM
def LetValue.mapFVarM [MonadLiftT CompilerM m] [Monad m] (f : FVarId → m FVarId) (e : LetValue) : m LetValue := do
match e with
| .value .. | .erased => return e
| .proj _ _ fvarId => return e.updateProj! (← f fvarId)
| .const _ _ args => return e.updateArgs! (← args.mapM (TraverseFVar.mapFVarM f))
| .fvar fvarId args => return e.updateFVar! (← f fvarId) (← args.mapM (TraverseFVar.mapFVarM f))
def LetValue.forFVarM [Monad m] (f : FVarId → m Unit) (e : LetValue) : m Unit := do
match e with
| .value .. | .erased => return ()
| .proj _ _ fvarId => f fvarId
| .const _ _ args => args.forM (TraverseFVar.forFVarM f)
| .fvar fvarId args => f fvarId; args.forM (TraverseFVar.forFVarM f)
instance : TraverseFVar LetValue where
mapFVarM := LetValue.mapFVarM
forFVarM := LetValue.forFVarM
partial def LetDecl.mapFVarM [MonadLiftT CompilerM m] [Monad m] (f : FVarId → m FVarId) (decl : LetDecl) : m LetDecl := do
decl.update (← Expr.mapFVarM f decl.type) (← LetValue.mapFVarM f decl.value)
partial def LetDecl.forFVarM [Monad m] (f : FVarId → m Unit) (decl : LetDecl) : m Unit := do
Expr.forFVarM f decl.type
LetValue.forFVarM f decl.value
instance : TraverseFVar LetDecl where
mapFVarM := LetDecl.mapFVarM
forFVarM := LetDecl.forFVarM
partial def Param.mapFVarM [MonadLiftT CompilerM m] [Monad m] (f : FVarId → m FVarId) (param : Param) : m Param := do
param.update (← Expr.mapFVarM f param.type)
partial def Param.forFVarM [Monad m] (f : FVarId → m Unit) (param : Param) : m Unit := do
Expr.forFVarM f param.type
instance : TraverseFVar Param where
mapFVarM := Param.mapFVarM
forFVarM := Param.forFVarM
partial def Code.mapFVarM [MonadLiftT CompilerM m] [Monad m] (f : FVarId → m FVarId) (c : Code) : m Code := do
match c with
| .let decl k =>
let decl ← LetDecl.mapFVarM f decl
return Code.updateLet! c decl (← mapFVarM f k)
| .fun decl k =>
let params ← decl.params.mapM (Param.mapFVarM f)
let decl ← decl.update (← Expr.mapFVarM f decl.type) params (← mapFVarM f decl.value)
return Code.updateFun! c decl (← mapFVarM f k)
| .jp decl k =>
let params ← decl.params.mapM (Param.mapFVarM f)
let decl ← decl.update (← Expr.mapFVarM f decl.type) params (← mapFVarM f decl.value)
return Code.updateFun! c decl (← mapFVarM f k)
| .cases cs =>
return Code.updateCases! c (← Expr.mapFVarM f cs.resultType) (← f cs.discr) (← cs.alts.mapM (·.mapCodeM (mapFVarM f)))
| .jmp fn args =>
return Code.updateJmp! c (← f fn) (← args.mapM (Arg.mapFVarM f))
| .return var =>
return Code.updateReturn! c (← f var)
| .unreach typ =>
return Code.updateUnreach! c (← Expr.mapFVarM f typ)
partial def Code.forFVarM [Monad m] (f : FVarId → m Unit) (c : Code) : m Unit := do
match c with
| .let decl k =>
LetDecl.forFVarM f decl
forFVarM f k
| .fun decl k =>
decl.params.forM (Param.forFVarM f)
Expr.forFVarM f decl.type
forFVarM f decl.value
forFVarM f k
| .jp decl k =>
decl.params.forM (Param.forFVarM f)
Expr.forFVarM f decl.type
forFVarM f decl.value
forFVarM f k
| .cases cs =>
Expr.forFVarM f cs.resultType
f cs.discr
cs.alts.forM (·.forCodeM (forFVarM f))
| .jmp fn args =>
f fn
args.forM (Arg.forFVarM f)
| .return var => f var
| .unreach typ =>
Expr.forFVarM f typ
instance : TraverseFVar Code where
mapFVarM := Code.mapFVarM
forFVarM := Code.forFVarM
def FunDecl.mapFVarM [MonadLiftT CompilerM m] [Monad m] (f : FVarId → m FVarId) (decl : FunDecl) : m FunDecl := do
let params ← decl.params.mapM (Param.mapFVarM f)
decl.update (← Expr.mapFVarM f decl.type) params (← Code.mapFVarM f decl.value)
def FunDecl.forFVarM [Monad m] (f : FVarId → m Unit) (decl : FunDecl) : m Unit := do
decl.params.forM (Param.forFVarM f)
Expr.forFVarM f decl.type
Code.forFVarM f decl.value
instance : TraverseFVar FunDecl where
mapFVarM := FunDecl.mapFVarM
forFVarM := FunDecl.forFVarM
instance : TraverseFVar CodeDecl where
mapFVarM f decl := do
match decl with
| .fun decl => return .fun (← mapFVarM f decl)
| .jp decl => return .jp (← mapFVarM f decl)
| .let decl => return .let (← mapFVarM f decl)
forFVarM f decl :=
match decl with
| .fun decl => forFVarM f decl
| .jp decl => forFVarM f decl
| .let decl => forFVarM f decl
instance : TraverseFVar Alt where
mapFVarM f alt := do
match alt with
| .alt ctor params c =>
let params ← params.mapM (Param.mapFVarM f)
return .alt ctor params (← Code.mapFVarM f c)
| .default c => return .default (← Code.mapFVarM f c)
forFVarM f alt := do
match alt with
| .alt _ params c =>
params.forM (Param.forFVarM f)
Code.forFVarM f c
| .default c => Code.forFVarM f c
def anyFVarM [Monad m] [TraverseFVar α] (f : FVarId → m Bool) (x : α) : m Bool := do
return (← TraverseFVar.forFVarM go x |>.run) matches none
where
go (fvar : FVarId) : OptionT m Unit := do
if (← f fvar) then failure
def allFVarM [Monad m] [TraverseFVar α] (f : FVarId → m Bool) (x : α) : m Bool := do
return (← TraverseFVar.forFVarM go x |>.run) matches .some ..
where
go (fvar : FVarId) : OptionT m Unit := do
if !(← f fvar) then failure
def anyFVar [TraverseFVar α] (f : FVarId → Bool) (x : α) : Bool :=
Id.run <| anyFVarM f x
def allFVar [TraverseFVar α] (f : FVarId → Bool) (x : α) : Bool :=
Id.run <| allFVarM f x
end Lean.Compiler.LCNF