434 lines
14 KiB
Text
434 lines
14 KiB
Text
/-
|
||
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Leonardo de Moura
|
||
-/
|
||
prelude
|
||
import Init.Lean.Level
|
||
import Init.Lean.KVMap
|
||
import Init.Data.HashMap
|
||
import Init.Data.PersistentHashMap
|
||
|
||
namespace Lean
|
||
|
||
inductive Literal
|
||
| natVal (val : Nat)
|
||
| strVal (val : String)
|
||
|
||
inductive BinderInfo
|
||
| default | implicit | strictImplicit | instImplicit | auxDecl
|
||
|
||
namespace BinderInfo
|
||
|
||
def isInstImplicit : BinderInfo → Bool
|
||
| instImplicit => true
|
||
| _ => false
|
||
|
||
protected def beq : BinderInfo → BinderInfo → Bool
|
||
| default, default => true
|
||
| implicit, implicit => true
|
||
| strictImplicit, strictImplicit => true
|
||
| instImplicit, instImplicit => true
|
||
| auxDecl, auxDecl => true
|
||
| _, _ => false
|
||
|
||
instance : HasBeq BinderInfo := ⟨BinderInfo.beq⟩
|
||
|
||
end BinderInfo
|
||
|
||
abbrev MData := KVMap
|
||
namespace MData
|
||
abbrev empty : MData := {KVMap .}
|
||
instance : HasEmptyc MData := ⟨empty⟩
|
||
end MData
|
||
|
||
/- We use the `E` suffix (short for `Expr`) to avoid collision with keywords.
|
||
We considered using «...», but it is too inconvenient to use. -/
|
||
inductive Expr
|
||
| bvar : Nat → Expr -- bound variables
|
||
| fvar : Name → Expr -- free variables
|
||
| mvar : Name → Expr -- meta variables
|
||
| sort : Level → Expr -- Sort
|
||
| const : Name → List Level → Expr -- constants
|
||
| app : Expr → Expr → Expr -- application
|
||
| lam : Name → BinderInfo → Expr → Expr → Expr -- lambda abstraction
|
||
| forallE : Name → BinderInfo → Expr → Expr → Expr -- (dependent) arrow
|
||
| letE : Name → Expr → Expr → Expr → Expr -- let expressions
|
||
| lit : Literal → Expr -- literals
|
||
| mdata : MData → Expr → Expr -- metadata
|
||
| proj : Name → Nat → Expr → Expr -- projection
|
||
|
||
instance exprIsInhabited : Inhabited Expr :=
|
||
⟨Expr.sort Level.zero⟩
|
||
|
||
attribute [extern "lean_expr_mk_bvar"] Expr.bvar
|
||
attribute [extern "lean_expr_mk_fvar"] Expr.fvar
|
||
attribute [extern "lean_expr_mk_mvar"] Expr.mvar
|
||
attribute [extern "lean_expr_mk_sort"] Expr.sort
|
||
attribute [extern "lean_expr_mk_const"] Expr.const
|
||
attribute [extern "lean_expr_mk_app"] Expr.app
|
||
attribute [extern "lean_expr_mk_lambda"] Expr.lam
|
||
attribute [extern "lean_expr_mk_forall"] Expr.forallE
|
||
attribute [extern "lean_expr_mk_let"] Expr.letE
|
||
attribute [extern "lean_expr_mk_lit"] Expr.lit
|
||
attribute [extern "lean_expr_mk_mdata"] Expr.mdata
|
||
attribute [extern "lean_expr_mk_proj"] Expr.proj
|
||
|
||
-- deprecated Constructor
|
||
@[extern "lean_expr_local"]
|
||
constant Expr.local (n : Name) (pp : Name) (ty : Expr) (bi : BinderInfo) : Expr := default _
|
||
|
||
def mkApp (fn : Expr) (args : Array Expr) : Expr :=
|
||
args.foldl Expr.app fn
|
||
|
||
def mkCApp (fn : Name) (args : Array Expr) : Expr :=
|
||
mkApp (Expr.const fn []) args
|
||
|
||
def mkAppRev (fn : Expr) (revArgs : Array Expr) : Expr :=
|
||
revArgs.foldr (fun a r => Expr.app r a) fn
|
||
|
||
namespace Expr
|
||
@[extern "lean_expr_hash"]
|
||
constant hash (n : @& Expr) : USize := default USize
|
||
|
||
instance : Hashable Expr := ⟨Expr.hash⟩
|
||
|
||
-- TODO: implement it in Lean
|
||
@[extern "lean_expr_dbg_to_string"]
|
||
constant dbgToString (e : @& Expr) : String := default String
|
||
|
||
@[extern "lean_expr_quick_lt"]
|
||
constant quickLt (a : @& Expr) (b : @& Expr) : Bool := default _
|
||
|
||
@[extern "lean_expr_lt"]
|
||
constant lt (a : @& Expr) (b : @& Expr) : Bool := default _
|
||
|
||
/- Return true iff `a` and `b` are alpha equivalent.
|
||
Binder annotations are ignored. -/
|
||
@[extern "lean_expr_eqv"]
|
||
constant eqv (a : @& Expr) (b : @& Expr) : Bool := default _
|
||
|
||
instance : HasBeq Expr := ⟨Expr.eqv⟩
|
||
|
||
/- Return true iff `a` and `b` are equal.
|
||
Binder names and annotations are taking into account. -/
|
||
@[extern "lean_expr_equal"]
|
||
constant equal (a : @& Expr) (b : @& Expr) : Bool := default _
|
||
|
||
@[extern "lean_expr_has_expr_mvar"]
|
||
constant hasExprMVar (a : @& Expr) : Bool := default _
|
||
|
||
@[extern "lean_expr_has_level_mvar"]
|
||
constant hasLevelMVar (a : @& Expr) : Bool := default _
|
||
|
||
@[inline] def hasMVar (a : Expr) : Bool :=
|
||
a.hasExprMVar || a.hasLevelMVar
|
||
|
||
@[extern "lean_expr_has_fvar"]
|
||
constant hasFVar (a : @& Expr) : Bool := default _
|
||
|
||
def isSort : Expr → Bool
|
||
| sort _ => true
|
||
| _ => false
|
||
|
||
def isBVar : Expr → Bool
|
||
| bvar _ => true
|
||
| _ => false
|
||
|
||
def isMVar : Expr → Bool
|
||
| mvar _ => true
|
||
| _ => false
|
||
|
||
def isFVar : Expr → Bool
|
||
| fvar _ => true
|
||
| _ => false
|
||
|
||
def isApp : Expr → Bool
|
||
| app _ _ => true
|
||
| _ => false
|
||
|
||
def isProj : Expr → Bool
|
||
| proj _ _ _ => true
|
||
| _ => false
|
||
|
||
def isConst : Expr → Bool
|
||
| const _ _ => true
|
||
| _ => false
|
||
|
||
def isForall : Expr → Bool
|
||
| forallE _ _ _ _ => true
|
||
| _ => false
|
||
|
||
def isLambda : Expr → Bool
|
||
| lam _ _ _ _ => true
|
||
| _ => false
|
||
|
||
def isBinding : Expr → Bool
|
||
| lam _ _ _ _ => true
|
||
| forallE _ _ _ _ => true
|
||
| _ => false
|
||
|
||
def isLet : Expr → Bool
|
||
| letE _ _ _ _ => true
|
||
| _ => false
|
||
|
||
def isMData : Expr → Bool
|
||
| mdata _ _ => true
|
||
| _ => false
|
||
|
||
def getAppFn : Expr → Expr
|
||
| app f a => getAppFn f
|
||
| e => e
|
||
|
||
def getAppNumArgsAux : Expr → Nat → Nat
|
||
| app f a, n => getAppNumArgsAux f (n+1)
|
||
| e, n => n
|
||
|
||
def getAppNumArgs (e : Expr) : Nat :=
|
||
getAppNumArgsAux e 0
|
||
|
||
private def getAppArgsAux : Expr → Array Expr → Nat → Array Expr
|
||
| app f a, as, i => getAppArgsAux f (as.set! i a) (i-1)
|
||
| _, as, _ => as
|
||
|
||
@[inline] def getAppArgs (e : Expr) : Array Expr :=
|
||
let dummy := Expr.sort Level.zero;
|
||
let nargs := e.getAppNumArgs;
|
||
getAppArgsAux e (mkArray nargs dummy) (nargs-1)
|
||
|
||
private def getAppRevArgsAux : Expr → Array Expr → Array Expr
|
||
| app f a, as => getAppRevArgsAux f (as.push a)
|
||
| _, as => as
|
||
|
||
@[inline] def getAppRevArgs (e : Expr) : Array Expr :=
|
||
getAppRevArgsAux e (Array.mkEmpty e.getAppNumArgs)
|
||
|
||
@[specialize] def withAppAux {α} (k : Expr → Array Expr → α) : Expr → Array Expr → Nat → α
|
||
| app f a, as, i => withAppAux f (as.set! i a) (i-1)
|
||
| f, as, i => k f as
|
||
|
||
@[inline] def withApp {α} (e : Expr) (k : Expr → Array Expr → α) : α :=
|
||
let dummy := Expr.sort Level.zero;
|
||
let nargs := e.getAppNumArgs;
|
||
withAppAux k e (mkArray nargs dummy) (nargs-1)
|
||
|
||
def isAppOf (e : Expr) (n : Name) : Bool :=
|
||
match e.getAppFn with
|
||
| const c _ => c == n
|
||
| _ => false
|
||
|
||
def isAppOfArity : Expr → Name → Nat → Bool
|
||
| const c _, n, 0 => c == n
|
||
| app f _, n, a+1 => isAppOfArity f n a
|
||
| _, _, _ => false
|
||
|
||
def constName : Expr → Name
|
||
| const n _ => n
|
||
| _ => panic! "constant expected"
|
||
|
||
def constLevels : Expr → List Level
|
||
| const _ ls => ls
|
||
| _ => panic! "constant expected"
|
||
|
||
def bvarIdx : Expr → Nat
|
||
| bvar idx => idx
|
||
| _ => panic! "bvar expected"
|
||
|
||
def fvarName : Expr → Name
|
||
| fvar n => n
|
||
| _ => panic! "fvar expected"
|
||
|
||
def bindingName : Expr → Name
|
||
| forallE n _ _ _ => n
|
||
| lam n _ _ _ => n
|
||
| _ => panic! "binding expected"
|
||
|
||
def bindingDomain : Expr → Expr
|
||
| forallE _ _ d _ => d
|
||
| lam _ _ d _ => d
|
||
| _ => panic! "binding expected"
|
||
|
||
def bindingBody : Expr → Expr
|
||
| forallE _ _ _ b => b
|
||
| lam _ _ _ b => b
|
||
| _ => panic! "binding expected"
|
||
|
||
def letName : Expr → Name
|
||
| letE n _ _ _ => n
|
||
| _ => panic! "let expression expected"
|
||
|
||
/-- Instantiate the loose bound variables in `e` using `subst`.
|
||
That is, a loose `Expr.bvar i` is replaced with `subst[i]`. -/
|
||
@[extern "lean_expr_instantiate"]
|
||
constant instantiate (e : @& Expr) (subst : @& Array Expr) : Expr := default _
|
||
|
||
@[extern "lean_expr_instantiate1"]
|
||
constant instantiate1 (e : @& Expr) (subst : @& Expr) : Expr := default _
|
||
|
||
/-- Similar to instantiate, but `Expr.bvar i` is replaced with `subst[subst.size - i - 1]` -/
|
||
@[extern "lean_expr_instantiate_rev"]
|
||
constant instantiateRev (e : @& Expr) (subst : @& Array Expr) : Expr := default _
|
||
|
||
/-- Similar to `instantiate`, but consider only the variables `xs` in the range `[beginIdx, endIdx)`.
|
||
Function panics if `beginIdx <= endIdx <= xs.size` does not hold. -/
|
||
@[extern "lean_expr_instantiate_range"]
|
||
constant instantiateRange (e : @& Expr) (beginIdx endIdx : @& Nat) (xs : Array Expr) : Expr := default _
|
||
|
||
/-- Replace free variables `xs` with loose bound variables. -/
|
||
@[extern "lean_expr_abstract"]
|
||
constant abstract (e : @& Expr) (xs : @& Array Expr) : Expr := default _
|
||
|
||
/-- Similar to `abstract`, but consider only the first `min n xs.size` entries in `xs`. -/
|
||
@[extern "lean_expr_abstract_range"]
|
||
constant abstractRange (e : @& Expr) (n : @& Nat) (xs : @& Array Expr) : Expr := default _
|
||
|
||
instance : HasToString Expr :=
|
||
⟨Expr.dbgToString⟩
|
||
|
||
-- TODO: should not use dbgToString, but constructors.
|
||
instance : HasRepr Expr :=
|
||
⟨Expr.dbgToString⟩
|
||
|
||
end Expr
|
||
|
||
def mkConst (n : Name) (ls : List Level := []) : Expr :=
|
||
Expr.const n ls
|
||
|
||
def mkBinApp (f a b : Expr) :=
|
||
Expr.app (Expr.app f a) b
|
||
|
||
def mkBinCApp (f : Name) (a b : Expr) :=
|
||
mkBinApp (mkConst f) a b
|
||
|
||
def mkDecIsTrue (pred proof : Expr) :=
|
||
mkBinApp (Expr.const `Decidable.isTrue []) pred proof
|
||
|
||
def mkDecIsFalse (pred proof : Expr) :=
|
||
mkBinApp (Expr.const `Decidable.isFalse []) pred proof
|
||
|
||
abbrev ExprMap (α : Type) := HashMap Expr α
|
||
abbrev PersistentExprMap (α : Type) := PHashMap Expr α
|
||
|
||
/- Auxiliary type for forcing `==` to be structural equality for `Expr` -/
|
||
structure ExprStructEq :=
|
||
(val : Expr)
|
||
|
||
instance exprToExprStructEq : HasCoe Expr ExprStructEq := ⟨ExprStructEq.mk⟩
|
||
|
||
namespace ExprStructEq
|
||
|
||
protected def beq : ExprStructEq → ExprStructEq → Bool
|
||
| ⟨e₁⟩, ⟨e₂⟩ => Expr.equal e₁ e₂
|
||
|
||
protected def hash : ExprStructEq → USize
|
||
| ⟨e⟩ => e.hash
|
||
|
||
instance : Inhabited ExprStructEq := ⟨{ val := default _ }⟩
|
||
instance : HasBeq ExprStructEq := ⟨ExprStructEq.beq⟩
|
||
instance : Hashable ExprStructEq := ⟨ExprStructEq.hash⟩
|
||
instance : HasToString ExprStructEq := ⟨fun e => toString e.val⟩
|
||
instance : HasRepr ExprStructEq := ⟨fun e => repr e.val⟩
|
||
|
||
end ExprStructEq
|
||
|
||
abbrev ExprStructMap (α : Type) := HashMap ExprStructEq α
|
||
abbrev PersistentExprStructMap (α : Type) := PHashMap ExprStructEq α
|
||
|
||
namespace Expr
|
||
/- The update functions here are defined using C code. They will try to avoid
|
||
allocating new values using pointer equality.
|
||
The hypotheses `(h : e.is... = true)` are used to ensure Lean will not crash
|
||
at runtime.
|
||
The `update*!` functions are inlined and provide a convenient way of using the
|
||
update proofs without providing proofs.
|
||
Note that if they are used under a match-expression, the compiler will eliminate
|
||
the double-match. -/
|
||
|
||
@[extern "lean_expr_update_app"]
|
||
def updateApp (e : Expr) (newFn : Expr) (newArg : Expr) (h : e.isApp = true) : Expr :=
|
||
app newFn newArg
|
||
|
||
@[inline] def updateApp! (e : Expr) (newFn : Expr) (newArg : Expr) : Expr :=
|
||
match e with
|
||
| app fn arg => updateApp (app fn arg) newFn newArg rfl
|
||
| _ => panic! "application expected"
|
||
|
||
@[extern "lean_expr_update_const"]
|
||
def updateConst (e : Expr) (newLevels : List Level) (h : e.isConst = true) : Expr :=
|
||
const e.constName newLevels
|
||
|
||
@[inline] def updateConst! (e : Expr) (newLevels : List Level) : Expr :=
|
||
match e with
|
||
| const n ls => updateConst (const n ls) newLevels rfl
|
||
| _ => panic! "constant expected"
|
||
|
||
@[extern "lean_expr_update_sort"]
|
||
def updateSort (e : Expr) (newLevel : Level) (h : e.isSort = true) : Expr :=
|
||
sort newLevel
|
||
|
||
@[inline] def updateSort! (e : Expr) (newLevel : Level) : Expr :=
|
||
match e with
|
||
| sort l => updateSort (sort l) newLevel rfl
|
||
| _ => panic! "level expected"
|
||
|
||
@[extern "lean_expr_update_proj"]
|
||
def updateProj (e : Expr) (newExpr : Expr) (h : e.isProj = true) : Expr :=
|
||
match e with
|
||
| proj s i _ => proj s i newExpr
|
||
| _ => e -- unreachable because of `h`
|
||
|
||
@[extern "lean_expr_update_mdata"]
|
||
def updateMData (e : Expr) (newExpr : Expr) (h : e.isMData = true) : Expr :=
|
||
match e with
|
||
| mdata d _ => mdata d newExpr
|
||
| _ => e -- unreachable because of `h`
|
||
|
||
@[inline] def updateMData! (e : Expr) (newExpr : Expr) : Expr :=
|
||
match e with
|
||
| mdata d e => updateMData (mdata d e) newExpr rfl
|
||
| _ => panic! "mdata expected"
|
||
|
||
@[inline] def updateProj! (e : Expr) (newExpr : Expr) : Expr :=
|
||
match e with
|
||
| proj s i e => updateProj (proj s i e) newExpr rfl
|
||
| _ => panic! "proj expected"
|
||
|
||
@[extern "lean_expr_update_forall"]
|
||
def updateForall (e : Expr) (newBinfo : BinderInfo) (newDomain : Expr) (newBody : Expr) (h : e.isForall = true) : Expr :=
|
||
forallE e.bindingName newBinfo newDomain newBody
|
||
|
||
@[inline] def updateForall! (e : Expr) (newBinfo : BinderInfo) (newDomain : Expr) (newBody : Expr) : Expr :=
|
||
match e with
|
||
| forallE n bi d b => updateForall (forallE n bi d b) newBinfo newDomain newBody rfl
|
||
| _ => panic! "forall expected"
|
||
|
||
@[inline] def updateForallE! (e : Expr) (newDomain : Expr) (newBody : Expr) : Expr :=
|
||
match e with
|
||
| forallE n bi d b => updateForall (forallE n bi d b) bi newDomain newBody rfl
|
||
| _ => panic! "forall expected"
|
||
|
||
@[extern "lean_expr_update_lambda"]
|
||
def updateLambda (e : Expr) (newBinfo : BinderInfo) (newDomain : Expr) (newBody : Expr) (h : e.isLambda = true) : Expr :=
|
||
lam e.bindingName newBinfo newDomain newBody
|
||
|
||
@[inline] def updateLambda! (e : Expr) (newBinfo : BinderInfo) (newDomain : Expr) (newBody : Expr) : Expr :=
|
||
match e with
|
||
| lam n bi d b => updateLambda (lam n bi d b) newBinfo newDomain newBody rfl
|
||
| _ => panic! "lambda expected"
|
||
|
||
@[inline] def updateLambdaE! (e : Expr) (newDomain : Expr) (newBody : Expr) : Expr :=
|
||
match e with
|
||
| lam n bi d b => updateLambda (lam n bi d b) bi newDomain newBody rfl
|
||
| _ => panic! "lambda expected"
|
||
|
||
@[extern "lean_expr_update_let"]
|
||
def updateLet (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) (h : e.isLet = true) : Expr :=
|
||
letE e.letName newType newVal newBody
|
||
|
||
@[inline] def updateLet! (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) : Expr :=
|
||
match e with
|
||
| letE n t v b => updateLet (letE n t v b) newType newVal newBody rfl
|
||
| _ => panic! "let expression expected"
|
||
|
||
end Expr
|
||
end Lean
|