lean4-htt/src/Lean/Compiler/LCNF/FVarUtil.lean
2022-11-07 16:18:36 -08:00

212 lines
7.7 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
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 LetExpr.mapFVarM [MonadLiftT CompilerM m] [Monad m] (f : FVarId → m FVarId) (e : LetExpr) : m LetExpr := 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 LetExpr.forFVarM [Monad m] (f : FVarId → m Unit) (e : LetExpr) : 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 LetExpr where
mapFVarM := LetExpr.mapFVarM
forFVarM := LetExpr.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) (← LetExpr.mapFVarM f decl.value)
partial def LetDecl.forFVarM [Monad m] (f : FVarId → m Unit) (decl : LetDecl) : m Unit := do
Expr.forFVarM f decl.type
LetExpr.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