blob: 9abc4fb15d07f8f1992de3bd50bcab240e09cb23 [file]
/-
Copyright (c) 2022 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean.Compiler.LCNF.Basic
namespace Lean.Compiler.LCNF
namespace ToExpr
private abbrev LevelMap := FVarIdMap Nat
private def _root_.Lean.FVarId.toExpr (offset : Nat) (m : LevelMap) (fvarId : FVarId) : Expr :=
match m.find? fvarId with
| some level => .bvar (offset - level - 1)
| none => .fvar fvarId
private def _root_.Lean.Expr.abstract' (offset : Nat) (m : LevelMap) (e : Expr) : Expr :=
go offset e
where
go (o : Nat) (e : Expr) : Expr :=
match e with
| .fvar fvarId => fvarId.toExpr o m
| .lit .. | .const .. | .sort .. | .mvar .. | .bvar .. => e
| .app f a => .app (go o f) (go o a)
| .mdata k b => .mdata k (go o b)
| .proj s i b => .proj s i (go o b)
| .forallE n d b bi => .forallE n (go o d) (go (o+1) b) bi
| .lam n d b bi => .lam n (go o d) (go (o+1) b) bi
| .letE n t v b nd => .letE n (go o t) (go o v) (go (o+1) b) nd
abbrev ToExprM := ReaderT Nat $ StateM LevelMap
abbrev mkLambdaM (params : Array Param) (e : Expr) : ToExprM Expr :=
return go (← read) (← get) params.size e
where
go (offset : Nat) (m : LevelMap) (i : Nat) (e : Expr) : Expr :=
if i > 0 then
let param := params[i-1]!
let domain := param.type.abstract' (offset - 1) m
go (offset - 1) m (i - 1) (.lam param.binderName domain e .default)
else
e
private abbrev _root_.Lean.FVarId.toExprM (fvarId : FVarId) : ToExprM Expr :=
return fvarId.toExpr (← read) (← get)
abbrev abstractM (e : Expr) : ToExprM Expr :=
return e.abstract' (← read) (← get)
@[inline] def withFVar (fvarId : FVarId) (k : ToExprM α) : ToExprM α := do
let offset ← read
modify fun s => s.insert fvarId offset
withReader (·+1) k
@[inline] partial def withParams (params : Array Param) (k : ToExprM α) : ToExprM α :=
go 0
where
@[specialize] go (i : Nat) : ToExprM α := do
if h : i < params.size then
withFVar params[i].fvarId (go (i+1))
else
k
@[inline] def run (x : ToExprM α) (offset : Nat := 0) (levelMap : LevelMap := {}) : α :=
x |>.run offset |>.run' levelMap
@[inline] def run' (x : ToExprM α) (xs : Array FVarId) : α :=
let map := xs.foldl (init := {}) fun map x => map.insert x map.size
run x xs.size map
end ToExpr
open ToExpr
private def Arg.toExprM (arg : Arg) : ToExprM Expr :=
return arg.toExpr.abstract' (← read) (← get)
mutual
partial def FunDeclCore.toExprM (decl : FunDecl) : ToExprM Expr :=
withParams decl.params do mkLambdaM decl.params (← decl.value.toExprM)
partial def Code.toExprM (code : Code) : ToExprM Expr := do
match code with
| .let decl k =>
let type ← abstractM decl.type
let value ← abstractM decl.value.toExpr
let body ← withFVar decl.fvarId k.toExprM
return .letE decl.binderName type value body true
| .fun decl k | .jp decl k =>
let type ← abstractM decl.type
let value ← decl.toExprM
let body ← withFVar decl.fvarId k.toExprM
return .letE decl.binderName type value body true
| .return fvarId => fvarId.toExprM
| .jmp fvarId args => return mkAppN (← fvarId.toExprM) (← args.mapM Arg.toExprM)
| .unreach type => return mkApp (mkConst ``lcUnreachable) (← abstractM type)
| .cases c =>
let alts ← c.alts.mapM fun
| .alt _ params k => withParams params do mkLambdaM params (← k.toExprM)
| .default k => k.toExprM
return mkAppN (mkConst `cases) (#[← c.discr.toExprM] ++ alts)
end
def Code.toExpr (code : Code) (xs : Array FVarId := #[]) : Expr :=
run' code.toExprM xs
def FunDeclCore.toExpr (decl : FunDecl) (xs : Array FVarId := #[]) : Expr :=
run' decl.toExprM xs
def Decl.toExpr (decl : Decl) : Expr :=
run do withParams decl.params do mkLambdaM decl.params (← decl.value.toExprM)
end Lean.Compiler.LCNF