/- 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