lean4-htt/Lake/Load/Package.lean
2022-08-04 16:58:42 -04:00

119 lines
4.9 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) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.DSL.Attributes
import Lake.Config.Workspace
/-!
This module contains definitions to load configuration objects from
a package configuration file (e.g., `lakefile.lean`).
-/
namespace Lake
open Lean System
/-- Unsafe implementation of `evalConstCheck`. -/
unsafe def unsafeEvalConstCheck (env : Environment) (opts : Options) (α) (type : Name) (const : Name) : Except String α :=
match env.find? const with
| none => throw s!"unknown constant '{const}'"
| some info =>
match info.type with
| Expr.const c _ =>
if c != type then
throwUnexpectedType
else
env.evalConst α opts const
| _ => throwUnexpectedType
where
throwUnexpectedType : Except String α :=
throw s!"unexpected type at '{const}', `{type}` expected"
/-- Like `Lean.Environment.evalConstCheck`, but with plain universe-polymorphic `Except`. -/
@[implementedBy unsafeEvalConstCheck] opaque evalConstCheck
(env : Environment) (opts : Options) (α) (type : Name) (const : Name) : Except String α
/-- Construct a `NameMap` from the declarations tagged with `attr`. -/
def mkTagMap
(env : Environment) (attr : TagAttribute)
[Monad m] (f : Name → m α) : m (NameMap α) :=
attr.ext.getState env |>.foldM (init := {}) fun map declName =>
return map.insert declName <| ← f declName
/-- Construct a `DNameMap` from the declarations tagged with `attr`. -/
def mkDTagMap
(env : Environment) (attr : TagAttribute)
[Monad m] (f : (n : Name) → m (β n)) : m (DNameMap β) :=
attr.ext.getState env |>.foldM (init := {}) fun map declName =>
return map.insert declName <| ← f declName
/-- Load a `PackageConfig` from a configuration environment. -/
def PackageConfig.loadFromEnv
(env : Environment) (opts := Options.empty) : Except String PackageConfig := do
let declName ←
match packageAttr.ext.getState env |>.toList with
| [] => error s!"configuration file is missing a `package` declaration"
| [name] => pure name
| _ => error s!"configuration file has multiple `package` declarations"
evalConstCheck env opts _ ``PackageConfig declName
/--
Load the remainder of a `Package`
from its configuration environment after resolving its dependencies.
-/
def Package.finalize (self : Package) (deps : Array Package) : LogIO Package := do
let env := self.configEnv; let opts := self.leanOpts
-- Load Script, Facet, & Target Configurations
let scripts : NameMap Script ← mkTagMap env scriptAttr fun name => do
let fn ← IO.ofExcept <| evalConstCheck env opts ScriptFn ``ScriptFn name
return {fn, doc? := (← findDocString? env name)}
let leanLibConfigs ← IO.ofExcept <| mkTagMap env leanLibAttr fun name =>
evalConstCheck env opts LeanLibConfig ``LeanLibConfig name
let leanExeConfigs ← IO.ofExcept <| mkTagMap env leanExeAttr fun name =>
evalConstCheck env opts LeanExeConfig ``LeanExeConfig name
let externLibConfigs ← mkDTagMap env externLibAttr fun name =>
match evalConstCheck env opts ExternLibDecl ``ExternLibDecl name with
| .ok decl =>
if h : decl.pkg = self.config.name ∧ decl.name = name then
return h.1 ▸ h.2 ▸ decl.config
else
error s!"target was defined as `{decl.pkg}/{decl.name}`, but was registered as `{self.name}/{name}`"
| .error e => error e
let opaqueTargetConfigs ← mkDTagMap env targetAttr fun name =>
match evalConstCheck env opts TargetDecl ``TargetDecl name with
| .ok decl =>
if h : decl.pkg = self.config.name ∧ decl.name = name then
return OpaqueTargetConfig.mk <| h.1 ▸ h.2 ▸ decl.config
else
error s!"target was defined as `{decl.pkg}/{decl.name}`, but was registered as `{self.name}/{name}`"
| .error e => error e
let defaultTargets := defaultTargetAttr.ext.getState env |>.fold (·.push ·) #[]
-- Fill in the Package
return {self with
opaqueDeps := deps.map (.mk ·)
leanLibConfigs, leanExeConfigs, externLibConfigs
opaqueTargetConfigs, defaultTargets, scripts
}
/--
Load module/package facets into a `Workspace` from a configuration environment.
-/
def Workspace.addFacetsFromEnv
(env : Environment) (opts : Options) (self : Workspace) : Except String Workspace := do
let mut ws := self
for name in moduleFacetAttr.ext.getState env do
match evalConstCheck env opts ModuleFacetDecl ``ModuleFacetDecl name with
| .ok decl => ws := ws.addModuleFacetConfig <| decl.config
| .error e => error e
for name in packageFacetAttr.ext.getState env do
match evalConstCheck env opts PackageFacetDecl ``PackageFacetDecl name with
| .ok decl => ws := ws.addPackageFacetConfig <| decl.config
| .error e => error e
for name in libraryFacetAttr.ext.getState env do
match evalConstCheck env opts LibraryFacetDecl ``LibraryFacetDecl name with
| .ok decl => ws := ws.addLibraryFacetConfig <| decl.config
| .error e => error e
return ws