ZAIDX11 commited on
Commit
ea5a2ee
·
verified ·
1 Parent(s): b0fb11a

Add files using upload-large-folder tool

Browse files
Files changed (20) hide show
  1. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Key.lean +53 -0
  2. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Meta.lean +63 -0
  3. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Package.lean +54 -0
  4. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Require.lean +70 -0
  5. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Script.lean +27 -0
  6. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Syntax.lean +419 -0
  7. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Targets.lean +257 -0
  8. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/VerLit.lean +47 -0
  9. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Config.lean +58 -0
  10. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Lean.lean +37 -0
  11. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Lean/Elab.lean +264 -0
  12. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Lean/Eval.lean +186 -0
  13. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Manifest.lean +290 -0
  14. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Materialize.lean +216 -0
  15. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Package.lean +92 -0
  16. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Resolve.lean +471 -0
  17. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Toml.lean +450 -0
  18. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Workspace.lean +58 -0
  19. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Toml/Data.lean +11 -0
  20. backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Toml/Decode.lean +208 -0
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Key.lean ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2025 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.Build.Key
8
+ import Lake.DSL.Syntax
9
+
10
+ /-! # DSL for Build Key
11
+ Notation for specifying build keys in a package.
12
+ -/
13
+
14
+ open Lean
15
+
16
+ namespace Lake.DSL
17
+
18
+ private def expandFacets (tgt : Term) (facets : Array Ident) : MacroM Term := do
19
+ let facetLits := facets.map fun facet => Name.quoteFrom facet facet.getId
20
+ facetLits.foldlM (init := tgt) fun tgt lit => `(BuildKey.facet $tgt $lit)
21
+
22
+ private def expandPackageTargetLit
23
+ (pkg : Term) (stx : TSyntax ``packageTargetLit)
24
+ : MacroM Term := withRef stx do
25
+ let `(packageTargetLit|$[+%$mod?]?$tgt) := stx
26
+ | Macro.throwError "ill-formed package target literal"
27
+ let tgtName :=
28
+ if mod?.isSome then
29
+ tgt.getId ++ PartialBuildKey.moduleTargetIndicator
30
+ else
31
+ tgt.getId
32
+ let tgtLit := Name.quoteFrom tgt tgtName
33
+ `(BuildKey.packageTarget $pkg $tgtLit)
34
+
35
+ macro_rules
36
+ | `(`+%$tk$mod$[:$facets]*) => withRef tk do
37
+ let modLit := Name.quoteFrom mod mod.getId
38
+ let tgt ← `(BuildKey.module $modLit)
39
+ let key ← expandFacets tgt facets
40
+ `(PartialBuildKey.mk $key)
41
+ | `(`@%$tk$(pkg?)?$[/$tgt?]?$[:$facets]*) => withRef tk do
42
+ let pkgLit :=
43
+ if let some pkg := pkg? then
44
+ Name.quoteFrom pkg pkg.getId
45
+ else
46
+ Name.quoteFrom tk Name.anonymous
47
+ let tgt ←
48
+ if let some tgt := tgt? then
49
+ expandPackageTargetLit pkgLit tgt
50
+ else
51
+ `(BuildKey.package $pkgLit)
52
+ let key ← expandFacets tgt facets
53
+ `(PartialBuildKey.mk $key)
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Meta.lean ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Eval
8
+ import Lean.Elab.ElabRules
9
+ import Lake.Util.FilePath
10
+ import Lake.DSL.Syntax
11
+
12
+ /-!
13
+ Syntax for elaboration time control flow.
14
+ -/
15
+
16
+ namespace Lake.DSL
17
+ open Lean Meta Elab Command Term
18
+
19
+ @[implemented_by Term.evalTerm]
20
+ opaque evalTerm (α) (type : Expr) (value : Syntax) (safety := DefinitionSafety.safe) : TermElabM α
21
+
22
+ def expandCmdDo : TSyntax ``cmdDo → Array Command
23
+ | `(cmdDo|do $cmds*) => cmds
24
+ | `(cmdDo|$cmd:command) => #[cmd]
25
+ | _ => #[]
26
+
27
+ @[builtin_command_elab metaIf]
28
+ def elabMetaIf : CommandElab := fun stx => do
29
+ let `(meta if $c then $t $[else $e?]?) := stx
30
+ | throwErrorAt stx "ill-formed meta if command"
31
+ if (← withRef c <| runTermElabM fun _ => evalTerm Bool (toTypeExpr Bool) c .unsafe) then
32
+ let cmd := mkNullNode (expandCmdDo t)
33
+ withMacroExpansion (← getRef) cmd <| elabCommand cmd
34
+ else if let some e := e? then
35
+ let cmd := mkNullNode (expandCmdDo e)
36
+ withMacroExpansion (← getRef) cmd <| elabCommand cmd
37
+
38
+ @[implemented_by Meta.evalExpr]
39
+ opaque evalExpr (α) (expectedType : Expr) (value : Expr) (safety := DefinitionSafety.safe) : MetaM α
40
+
41
+ def toExprIO [ToExpr α] (x : IO α) : IO Expr :=
42
+ toExpr <$> x
43
+
44
+ @[builtin_term_elab runIO]
45
+ def elabRunIO : TermElab := fun stx expectedType? =>
46
+ match stx with
47
+ | `(run_io%$tk $t) => withRef t do
48
+ let expectedType := mkApp (mkConst ``IO) <|
49
+ expectedType?.getD <| ← mkFreshExprMVar <| mkSort <| .succ .zero
50
+ let v ← elabTermEnsuringType (← `(do $t)) expectedType
51
+ synthesizeSyntheticMVarsNoPostponing
52
+ let v ← instantiateMVars v
53
+ if (← logUnassignedUsingErrorInfos (← getMVars v)) then
54
+ throwAbortTerm
55
+ let v ← mkAppM ``toExprIO #[v]
56
+ let io ← evalExpr (IO Expr) (mkApp (mkConst ``IO) (mkConst ``Expr)) v
57
+ let (out, x) ← IO.FS.withIsolatedStreams io.toBaseIO
58
+ unless out.isEmpty do
59
+ logInfoAt tk out
60
+ match x with
61
+ | .ok x => return x
62
+ | .error e => throwErrorAt tk e.toString
63
+ | _ => Elab.throwUnsupportedSyntax
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Package.lean ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.Config.Package
8
+ import Lake.DSL.Attributes
9
+ import Lake.DSL.DeclUtil
10
+ import Lake.DSL.Syntax
11
+
12
+ open Lean Parser Elab Command
13
+
14
+ namespace Lake.DSL
15
+
16
+ /-! # Package Declarations
17
+ DSL definitions for packages and hooks.
18
+ -/
19
+
20
+ @[builtin_command_elab packageCommand]
21
+ def elabPackageCommand : CommandElab := fun stx => do
22
+ let `(packageCommand|$(doc?)? $(attrs?)? package%$kw $[$nameStx?]? $cfg) := stx
23
+ | throwErrorAt stx "ill-formed package declaration"
24
+ withRef kw do
25
+ let configId : Ident ← `(pkgConfig)
26
+ let id ← mkConfigDeclIdent nameStx?
27
+ let name := Name.quoteFrom id id.getId
28
+ let ty := Syntax.mkCApp ``PackageConfig #[name]
29
+ elabConfig ``PackageConfig configId ty cfg
30
+ let attr ← `(Term.attrInstance| «package»)
31
+ let attrs := #[attr] ++ expandAttrs attrs?
32
+ let id := mkIdentFrom id packageDeclName
33
+ let decl ← `({name := $name, config := $configId})
34
+ let cmd ← `($[$doc?]? @[$attrs,*] abbrev $id : PackageDecl := $decl)
35
+ withMacroExpansion stx cmd <| elabCommand cmd
36
+
37
+ abbrev PackageCommand := TSyntax ``packageCommand
38
+
39
+ instance : Coe PackageCommand Command where
40
+ coe x := ⟨x.raw⟩
41
+
42
+ @[builtin_macro postUpdateDecl]
43
+ def expandPostUpdateDecl : Macro := fun stx => do
44
+ match stx with
45
+ | `($[$doc?]? $[$attrs?]? post_update%$kw $[$pkg?]? do $seq $[$wds?:whereDecls]?) =>
46
+ `($[$doc?]? $[$attrs?]? post_update%$kw $[$pkg?]? := do $seq $[$wds?:whereDecls]?)
47
+ | `($[$doc?]? $[$attrs?]? post_update%$kw $[$pkg?]? := $defn $[$wds?:whereDecls]?) => withRef kw do
48
+ let pkg ← expandOptSimpleBinder pkg?
49
+ let pkgName := mkIdentFrom pkg `_package.name
50
+ let attr ← `(Term.attrInstance| «post_update»)
51
+ let attrs := #[attr] ++ expandAttrs attrs?
52
+ `($[$doc?]? @[$attrs,*] def postUpdateHook : PostUpdateHookDecl :=
53
+ {pkg := $pkgName, fn := fun $pkg => $defn} $[$wds?:whereDecls]?)
54
+ | stx => Macro.throwErrorAt stx "ill-formed post_update declaration"
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Require.lean ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lean.Parser.Command
8
+ import Lake.Config.Dependency
9
+ import Lake.DSL.Extensions
10
+ import Lake.DSL.DeclUtil
11
+ import Lake.DSL.Syntax
12
+
13
+ open Lean Parser Command
14
+
15
+ namespace Lake.DSL
16
+
17
+ /-! # The `require` syntax
18
+
19
+ This module contains the expansion of the `require` DSL syntax used to specify package dependencies.
20
+ -/
21
+
22
+ @[inline] private def quoteOptTerm [Monad m] [MonadQuotation m] (term? : Option Term) : m Term :=
23
+ if let some term := term? then withRef term ``(some $term) else ``(none)
24
+
25
+ def expandDepSpec (stx : TSyntax ``depSpec) (doc? : Option DocComment) : MacroM Command := do
26
+ let `(depSpec| $fullNameStx $[@ $ver?]? $[from $src?]? $[with $opts?]?) := stx
27
+ | Macro.throwErrorAt stx "ill-formed require syntax"
28
+ let src? ← src?.mapM fun src =>
29
+ match src with
30
+ | `(fromSource|git%$tk $url $[@ $rev?]? $[/ $subDir?]?) => withRef tk do
31
+ let rev ← quoteOptTerm rev?
32
+ let subDir ← quoteOptTerm subDir?
33
+ ``(DependencySrc.git $url $rev $subDir)
34
+ | `(fromSource|$path:term) => withRef src do
35
+ ``(DependencySrc.path $path)
36
+ | _ => Macro.throwErrorAt src "ill-formed from syntax"
37
+ let `(depName|$[$scope? /]? $nameStx) := fullNameStx
38
+ | Macro.throwErrorAt fullNameStx "ill-formed name syntax"
39
+ let scope :=
40
+ match scope? with
41
+ | some scope => scope
42
+ | none => Syntax.mkStrLit "" (.fromRef fullNameStx)
43
+ let ver ←
44
+ if let some ver := ver? then withRef ver do
45
+ match ver with
46
+ | `(verSpec|git $ver) => ``(some ("git#" ++ $ver))
47
+ | `(verSpec|$ver:term) => ``(some $ver)
48
+ | _ => Macro.throwErrorAt ver "ill-formed version syntax"
49
+ else
50
+ ``(none)
51
+ let name := expandIdentOrStrAsIdent nameStx
52
+ `($[$doc?:docComment]? @[package_dep] def $name : $(mkCIdent ``Dependency) := {
53
+ name := $(quote name.getId),
54
+ scope := $scope,
55
+ version? := $ver,
56
+ src? := $(← quoteOptTerm src?),
57
+ opts := $(opts?.getD <| ← `({})),
58
+ })
59
+
60
+
61
+ @[builtin_macro requireDecl]
62
+ def expandRequireDecl : Macro := fun stx => do
63
+ let `(requireDecl|$(doc?)? require%$kw $spec) := stx
64
+ | Macro.throwErrorAt stx "ill-formed require declaration"
65
+ withRef kw do expandDepSpec spec doc?
66
+
67
+ @[inherit_doc requireDecl] abbrev RequireDecl := TSyntax ``requireDecl
68
+
69
+ instance : Coe RequireDecl Command where
70
+ coe x := ⟨x.raw⟩
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Script.lean ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.Config.Package
8
+ import Lake.DSL.Attributes
9
+ import Lake.DSL.Syntax
10
+
11
+ /-! # Script Declarations
12
+ DSL definitions to define a Lake script for a package.
13
+ -/
14
+
15
+ namespace Lake.DSL
16
+ open Lean Parser Command
17
+
18
+ @[builtin_macro scriptDecl]
19
+ def expandScriptDecl : Macro
20
+ | `($[$doc?]? $[$attrs?]? script%$kw $name $[$args?]? do $seq $[$wds?:whereDecls]?) => do
21
+ `($[$doc?]? $[$attrs?]? script%$kw $name $[$args?]? := do $seq $[$wds?:whereDecls]?)
22
+ | `($[$doc?]? $[$attrs?]? script%$kw $name $[$args?]? := $defn $[$wds?:whereDecls]?) => withRef kw do
23
+ let id := expandIdentOrStrAsIdent name
24
+ let args ← expandOptSimpleBinder args?
25
+ let attrs := #[← `(Term.attrInstance| «script»)] ++ expandAttrs attrs?
26
+ `($[$doc?]? @[$attrs,*] def $id : ScriptFn := fun $args => $defn $[$wds?:whereDecls]?)
27
+ | stx => Macro.throwErrorAt stx "ill-formed script declaration"
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Syntax.lean ADDED
@@ -0,0 +1,419 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.DSL.DeclUtil
8
+ import Lean.Parser.Term
9
+
10
+ open Lean Parser Elab Command
11
+
12
+ open System (FilePath)
13
+
14
+ /-!
15
+ This module defines the syntax of the Lake DSL. The syntax is defined separately from the elaborator
16
+ and/or macro definitions to allow clients to import it without crashing Lean. In particular, this
17
+ allows the reference manual to document the DSL syntax.
18
+ -/
19
+
20
+ namespace Lake.DSL
21
+
22
+ /--
23
+ A macro that expands to the path of package's directory
24
+ during the Lakefile's elaboration.
25
+ -/
26
+ scoped syntax (name := dirConst) "__dir__" : term
27
+
28
+ /--
29
+ A macro that expands to the specified configuration option (or `none`,
30
+ if the option has not been set) during the Lakefile's elaboration.
31
+
32
+ Configuration arguments are set either via the Lake CLI (by the `-K` option)
33
+ or via the `with` clause in a `require` statement.
34
+ -/
35
+ scoped syntax (name := getConfig) "get_config? " ident :term
36
+
37
+ /-!
38
+ # Package Declarations
39
+ DSL syntax definitions for packages and hooks.
40
+ -/
41
+
42
+ /--
43
+ Defines the configuration of a Lake package. Has many forms:
44
+
45
+ ```lean
46
+ package «pkg-name»
47
+ package «pkg-name» { /- config opts -/ }
48
+ package «pkg-name» where /- config opts -/
49
+ ```
50
+
51
+ There can only be one `package` declaration per Lake configuration file.
52
+ The defined package configuration will be available for reference as `_package`.
53
+ -/
54
+ scoped syntax (name := packageCommand)
55
+ (docComment)? (Term.attributes)? "package " (identOrStr)? optConfig : command
56
+
57
+ /--
58
+ Declare a post-`lake update` hook for the package.
59
+ Runs the monadic action is after a successful `lake update` execution
60
+ in this package or one of its downstream dependents.
61
+
62
+ **Example**
63
+
64
+ This feature enables Mathlib to synchronize the Lean toolchain and run
65
+ `cache get` after a `lake update`:
66
+
67
+ ```
68
+ lean_exe cache
69
+ post_update pkg do
70
+ let wsToolchainFile := (← getRootPackage).dir / "lean-toolchain"
71
+ let mathlibToolchain ← IO.FS.readFile <| pkg.dir / "lean-toolchain"
72
+ IO.FS.writeFile wsToolchainFile mathlibToolchain
73
+ let exeFile ← runBuild cache.fetch
74
+ let exitCode ← env exeFile.toString #["get"]
75
+ if exitCode ≠ 0 then
76
+ error s!"{pkg.name}: failed to fetch cache"
77
+ ```
78
+ -/
79
+ scoped syntax (name := postUpdateDecl)
80
+ optional(docComment) optional(Term.attributes)
81
+ "post_update " (ppSpace simpleBinder)? (declValSimple <|> declValDo)
82
+ : command
83
+
84
+
85
+ /-! # The `require` syntax
86
+
87
+ This is the `require` DSL syntax used to specify package dependencies.
88
+ -/
89
+
90
+ syntax fromPath :=
91
+ term
92
+
93
+ syntax fromGit :=
94
+ &"git " term:max ("@" term:max)? ("/" term)?
95
+
96
+ syntax fromSource :=
97
+ fromGit <|> fromPath
98
+
99
+ /--
100
+ Specifies a specific source from which to draw the package dependency.
101
+ Dependencies that are downloaded from a remote source will be placed
102
+ into the workspace's `packagesDir`.
103
+
104
+ **Path Dependencies**
105
+
106
+ ```
107
+ from <path>
108
+ ```
109
+
110
+ Lake loads the package located a fixed `path` relative to the
111
+ requiring package's directory.
112
+
113
+ **Git Dependencies**
114
+
115
+ ```
116
+ from git <url> [@ <rev>] [/ <subDir>]
117
+ ```
118
+
119
+ Lake clones the Git repository available at the specified fixed Git `url`,
120
+ and checks out the specified revision `rev`. The revision can be a commit hash,
121
+ branch, or tag. If none is provided, Lake defaults to `master`. After checkout,
122
+ Lake loads the package located in `subDir` (or the repository root if no
123
+ subdirectory is specified).
124
+ -/
125
+ syntax fromClause :=
126
+ " from " fromSource
127
+
128
+ /-
129
+ A `NameMap String` of Lake options used to configure the dependency.
130
+ This is equivalent to passing `-K` options to the dependency on the command line.
131
+ -/
132
+ syntax withClause :=
133
+ " with " term
134
+
135
+ syntax verSpec :=
136
+ &"git "? term:max
137
+
138
+ /--
139
+ The version of the package to require.
140
+ To specify a Git revision, use the syntax `@ git <rev>`.
141
+ -/
142
+ syntax verClause :=
143
+ " @ " verSpec
144
+
145
+ syntax depName :=
146
+ atomic(str " / ")? identOrStr
147
+
148
+ syntax depSpec :=
149
+ depName (verClause)? (fromClause)? (withClause)?
150
+
151
+ /--
152
+ Adds a new package dependency to the workspace. The general syntax is:
153
+
154
+ ```
155
+ require ["<scope>" /] <pkg-name> [@ <version>]
156
+ [from <source>] [with <options>]
157
+ ```
158
+
159
+ The `from` clause tells Lake where to locate the dependency.
160
+ See the `fromClause` syntax documentation (e.g., hover over it) to see
161
+ the different forms this clause can take.
162
+
163
+ Without a `from` clause, Lake will lookup the package in the default
164
+ registry (i.e., Reservoir) and use the information there to download the
165
+ package at the requested `version`. The `scope` is used to disambiguate between
166
+ packages in the registry with the same `pkg-name`. In Reservoir, this scope
167
+ is the package owner (e.g., `leanprover` of `@leanprover/doc-gen4`).
168
+
169
+ The `with` clause specifies a `NameMap String` of Lake options
170
+ used to configure the dependency. This is equivalent to passing `-K`
171
+ options to the dependency on the command line.
172
+ -/
173
+ scoped syntax (name := requireDecl)
174
+ (docComment)? "require " depSpec : command
175
+
176
+
177
+ /-!
178
+ # DSL for Targets & Facets
179
+ Syntax for declaring Lake targets and facets.
180
+ -/
181
+
182
+ syntax buildDeclSig :=
183
+ identOrStr (ppSpace simpleBinder)? Term.typeSpec declValSimple
184
+
185
+ /-!
186
+ ## Facet Declarations
187
+ -/
188
+
189
+ /--
190
+ Define a new module facet. Has one form:
191
+
192
+ ```lean
193
+ module_facet «facet-name» (mod : Module) : α :=
194
+ /- build term of type `FetchM (Job α)` -/
195
+ ```
196
+
197
+ The `mod` parameter (and its type specifier) is optional.
198
+ -/
199
+ scoped syntax (name := moduleFacetDecl)
200
+ (docComment)? (Term.attributes)? "module_facet " buildDeclSig : command
201
+
202
+ /--
203
+ Define a new package facet. Has one form:
204
+
205
+ ```lean
206
+ package_facet «facet-name» (pkg : Package) : α :=
207
+ /- build term of type `FetchM (Job α)` -/
208
+ ```
209
+
210
+ The `pkg` parameter (and its type specifier) is optional.
211
+ -/
212
+ scoped syntax (name := packageFacetDecl)
213
+ (docComment)? (Term.attributes)? "package_facet " buildDeclSig : command
214
+
215
+ /--
216
+ Define a new library facet. Has one form:
217
+
218
+ ```lean
219
+ library_facet «facet-name» (lib : LeanLib) : α :=
220
+ /- build term of type `FetchM (Job α)` -/
221
+ ```
222
+
223
+ The `lib` parameter (and its type specifier) is optional.
224
+ -/
225
+ scoped syntax (name := libraryFacetDecl)
226
+ (docComment)? (Term.attributes)? "library_facet " buildDeclSig : command
227
+
228
+
229
+ /-!
230
+ ## Custom Target Declaration
231
+ -/
232
+
233
+ /--
234
+ Define a new custom target for the package. Has one form:
235
+
236
+ ```lean
237
+ target «target-name» (pkg : NPackage _package.name) : α :=
238
+ /- build term of type `FetchM (Job α)` -/
239
+ ```
240
+
241
+ The `pkg` parameter (and its type specifier) is optional.
242
+ It is of type `NPackage _package.name` to provably demonstrate the package
243
+ provided is the package in which the target is defined.
244
+ -/
245
+ scoped syntax (name := targetCommand)
246
+ (docComment)? (Term.attributes)? "target " buildDeclSig : command
247
+
248
+
249
+ /-!
250
+ ## Lean Library & Executable Target Declarations
251
+ -/
252
+
253
+ /--
254
+ Define a new Lean library target for the package.
255
+ Can optionally be provided with a configuration of type `LeanLibConfig`.
256
+ Has many forms:
257
+
258
+ ```lean
259
+ lean_lib «target-name»
260
+ lean_lib «target-name» { /- config opts -/ }
261
+ lean_lib «target-name» where /- config opts -/
262
+ ```
263
+ -/
264
+ scoped syntax (name := leanLibCommand)
265
+ (docComment)? (Term.attributes)? "lean_lib " (identOrStr)? optConfig : command
266
+
267
+ /--
268
+ Define a new Lean binary executable target for the package.
269
+ Can optionally be provided with a configuration of type `LeanExeConfig`.
270
+ Has many forms:
271
+
272
+ ```lean
273
+ lean_exe «target-name»
274
+ lean_exe «target-name» { /- config opts -/ }
275
+ lean_exe «target-name» where /- config opts -/
276
+ ```
277
+ -/
278
+ scoped syntax (name := leanExeCommand)
279
+ (docComment)? (Term.attributes)? "lean_exe " (identOrStr)? optConfig : command
280
+
281
+ /--
282
+ Define a new input file target for the package.
283
+ Can optionally be provided with a configuration of type `InputFileConfig`.
284
+ -/
285
+ scoped syntax (name := inputFileCommand)
286
+ (docComment)? (Term.attributes)? "input_file " (identOrStr)? optConfig : command
287
+
288
+ /--
289
+ Define a new input directory target for the package.
290
+ Can optionally be provided with a configuration of type `InputDirConfig`.
291
+ -/
292
+ scoped syntax (name := inputDirCommand)
293
+ (docComment)? (Term.attributes)? "input_dir " (identOrStr)? optConfig : command
294
+
295
+ /-!
296
+ ## External Library Target Declaration
297
+ -/
298
+
299
+ syntax externLibDeclSpec :=
300
+ identOrStr (ppSpace simpleBinder)? declValSimple
301
+
302
+ /--
303
+ Define a new external library target for the package. Has one form:
304
+
305
+ ```lean
306
+ extern_lib «target-name» (pkg : NPackage _package.name) :=
307
+ /- build term of type `FetchM (Job FilePath)` -/
308
+ ```
309
+
310
+ The `pkg` parameter (and its type specifier) is optional.
311
+ It is of type `NPackage _package.name` to provably demonstrate the package
312
+ provided is the package in which the target is defined.
313
+
314
+ The term should build the external library's **static** library.
315
+ -/
316
+ scoped syntax (name := externLibCommand)
317
+ (docComment)? (Term.attributes)? "extern_lib " externLibDeclSpec : command
318
+
319
+ /-!
320
+ # Script Declarations
321
+
322
+ DSL definitions to define a Lake script for a package.
323
+ -/
324
+
325
+ syntax scriptDeclSpec :=
326
+ identOrStr (ppSpace simpleBinder)? (declValSimple <|> declValDo)
327
+
328
+ /--
329
+ Define a new Lake script for the package.
330
+
331
+ **Example**
332
+
333
+ ```
334
+ /-- Display a greeting -/
335
+ script «script-name» (args) do
336
+ if h : 0 < args.length then
337
+ IO.println s!"Hello, {args[0]'h}!"
338
+ else
339
+ IO.println "Hello, world!"
340
+ return 0
341
+ ```
342
+ -/
343
+ scoped syntax (name := scriptDecl)
344
+ (docComment)? optional(Term.attributes) "script " scriptDeclSpec : command
345
+
346
+ end DSL
347
+
348
+ /-!
349
+ # Version Literals
350
+
351
+ Defines the `v!"<ver>"` syntax for version literals.
352
+ -/
353
+
354
+ /-- A Lake version literal. -/
355
+ scoped syntax:max (name := verLit) "v!" noWs interpolatedStr(term) : term
356
+
357
+ namespace DSL
358
+
359
+ /-!
360
+ # DSL for Build Key
361
+
362
+ Notation for specifying build keys in a package.
363
+ -/
364
+
365
+ syntax facetSuffix := atomic(":" noWs) ident
366
+ syntax packageTargetLit := atomic("+" noWs)? ident
367
+
368
+ /-- A module target key literal (with optional facet). -/
369
+ scoped syntax:max "`+" noWs ident facetSuffix* : term
370
+
371
+ /-- A package target key literal (with optional facet). -/
372
+ scoped syntax:max "`@" (noWs ident)?
373
+ (atomic(noWs "/" noWs) packageTargetLit)? (noWs facetSuffix)* : term
374
+
375
+ /-!
376
+ # Elaboration-Time Control Flow
377
+
378
+ Syntax for elaboration time control flow.
379
+ -/
380
+
381
+ /--
382
+ The `do` command syntax groups multiple similarly indented commands together.
383
+ The group can then be passed to another command that usually only accepts a
384
+ single command (e.g., `meta if`).
385
+ -/
386
+ syntax cmdDo := ("do" many1Indent(command)) <|> command
387
+
388
+ /--
389
+ The `meta if` command has two forms:
390
+
391
+ ```lean
392
+ meta if <c:term> then <a:command>
393
+ meta if <c:term> then <a:command> else <b:command>
394
+ ```
395
+
396
+ It expands to the command `a` if the term `c` evaluates to true
397
+ (at elaboration time). Otherwise, it expands to command `b` (if an `else`
398
+ clause is provided).
399
+
400
+ One can use this command to specify, for example, external library targets
401
+ only available on specific platforms:
402
+
403
+ ```lean
404
+ meta if System.Platform.isWindows then
405
+ extern_lib winOnlyLib := ...
406
+ else meta if System.Platform.isOSX then
407
+ extern_lib macOnlyLib := ...
408
+ else
409
+ extern_lib linuxOnlyLib := ...
410
+ ```
411
+ -/
412
+ scoped syntax (name := metaIf)
413
+ "meta " "if " term " then " cmdDo (" else " cmdDo)? : command
414
+
415
+ /--
416
+ Executes a term of type `IO α` at elaboration-time
417
+ and produces an expression corresponding to the result via `ToExpr α`.
418
+ -/
419
+ scoped syntax:lead (name := runIO) "run_io " doSeq : term
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/Targets.lean ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.DSL.DeclUtil
8
+ import Lake.DSL.Syntax
9
+ import Lake.Config.FacetConfig
10
+ import Lake.Config.TargetConfig
11
+ import Lake.Build.Job
12
+
13
+
14
+ /-! # DSL for Targets & Facets
15
+ Macros for declaring Lake targets and facets.
16
+ -/
17
+
18
+ open System (FilePath)
19
+ open Lean Parser Elab Command
20
+
21
+ namespace Lake.DSL
22
+
23
+
24
+ --------------------------------------------------------------------------------
25
+ /-! ## Facet Declarations -/
26
+ --------------------------------------------------------------------------------
27
+
28
+ abbrev mkModuleFacetDecl
29
+ (α) (facet : Name)
30
+ [OptDataKind α] [FormatQuery α] [FamilyDef ModuleData facet α]
31
+ (f : Module → FetchM (Job α))
32
+ : ModuleFacetDecl := .mk (Module.facetKind ++ facet) <| mkFacetJobConfig fun mod => do
33
+ withRegisterJob (mod.facet facet |>.key.toSimpleString)
34
+ (f mod)
35
+
36
+ @[builtin_macro moduleFacetDecl]
37
+ def expandModuleFacetDecl : Macro := fun stx => do
38
+ let `(moduleFacetDecl|$(doc?)? $(attrs?)? module_facet%$kw $sig) := stx
39
+ | Macro.throwErrorAt stx "ill-formed module facet declaration"
40
+ let `(buildDeclSig| $nameStx $[$mod?]? : $ty := $defn $[$wds?:whereDecls]?) := sig
41
+ | Macro.throwErrorAt sig "ill-formed module facet declaration"
42
+ withRef kw do
43
+ let attr ← `(Term.attrInstance| «module_facet»)
44
+ let attrs := #[attr] ++ expandAttrs attrs?
45
+ let id := expandIdentOrStrAsIdent nameStx
46
+ let facet := Name.quoteFrom id id.getId
47
+ let declId := mkIdentFrom id <| id.getId.modifyBase (.str · "_modFacet")
48
+ let mod ← expandOptSimpleBinder mod?
49
+ `(module_data $id : $ty
50
+ $[$doc?:docComment]? @[$attrs,*] abbrev $declId :=
51
+ Lake.DSL.mkModuleFacetDecl $ty $facet (fun $mod => $defn)
52
+ $[$wds?:whereDecls]?)
53
+
54
+ abbrev mkPackageFacetDecl
55
+ (α) (facet : Name)
56
+ [OptDataKind α] [FormatQuery α] [FamilyDef PackageData facet α]
57
+ (f : Package → FetchM (Job α))
58
+ : PackageFacetDecl := .mk (Package.facetKind ++ facet) <| mkFacetJobConfig fun pkg => do
59
+ withRegisterJob (pkg.facet facet |>.key.toSimpleString)
60
+ (f pkg)
61
+
62
+ @[builtin_macro packageFacetDecl]
63
+ def expandPackageFacetDecl : Macro := fun stx => do
64
+ let `(packageFacetDecl|$(doc?)? $(attrs?)? package_facet%$kw $sig) := stx
65
+ | Macro.throwErrorAt stx "ill-formed package facet declaration"
66
+ let `(buildDeclSig| $nameStx $[$pkg?]? : $ty := $defn $[$wds?:whereDecls]?) := sig
67
+ | Macro.throwErrorAt sig "ill-formed package facet signature"
68
+ withRef kw do
69
+ let attr ← `(Term.attrInstance| «package_facet»)
70
+ let attrs := #[attr] ++ expandAttrs attrs?
71
+ let id := expandIdentOrStrAsIdent nameStx
72
+ let facet := Name.quoteFrom id id.getId
73
+ let declId := mkIdentFrom id <| id.getId.modifyBase (.str · "_pkgFacet")
74
+ let pkg ← expandOptSimpleBinder pkg?
75
+ `(package_data $id : $ty
76
+ $[$doc?]? @[$attrs,*] abbrev $declId :=
77
+ Lake.DSL.mkPackageFacetDecl $ty $facet (fun $pkg => $defn)
78
+ $[$wds?:whereDecls]?)
79
+
80
+ abbrev mkLibraryFacetDecl
81
+ (α) (facet : Name)
82
+ [OptDataKind α] [FormatQuery α] [FamilyDef LibraryData facet α]
83
+ (f : LeanLib → FetchM (Job α))
84
+ : LibraryFacetDecl := .mk (LeanLib.facetKind ++ facet) <| mkFacetJobConfig fun lib => do
85
+ withRegisterJob (lib.facet facet |>.key.toSimpleString)
86
+ (f lib)
87
+
88
+ @[builtin_macro libraryFacetDecl]
89
+ def expandLibraryFacetDecl : Macro := fun stx => do
90
+ let `(libraryFacetDecl|$(doc?)? $(attrs?)? library_facet%$kw $sig) := stx
91
+ | Macro.throwErrorAt stx "ill-formed library facet declaration"
92
+ let `(buildDeclSig| $nameStx $[$lib?]? : $ty := $defn $[$wds?:whereDecls]?) := sig
93
+ | Macro.throwErrorAt sig "ill-formed library facet signature"
94
+ withRef kw do
95
+ let attr ← `(Term.attrInstance| «library_facet»)
96
+ let attrs := #[attr] ++ expandAttrs attrs?
97
+ let id := expandIdentOrStrAsIdent nameStx
98
+ let facet := Name.quoteFrom id id.getId
99
+ let declId := mkIdentFrom id <| id.getId.modifyBase (.str · "_libFacet")
100
+ let lib ← expandOptSimpleBinder lib?
101
+ `(library_data $id : $ty
102
+ $[$doc?]? @[$attrs,*] abbrev $declId : LibraryFacetDecl :=
103
+ Lake.DSL.mkLibraryFacetDecl $ty $facet (fun $lib => $defn)
104
+ $[$wds?:whereDecls]?)
105
+
106
+
107
+ --------------------------------------------------------------------------------
108
+ /-! ## Custom Target Declaration -/
109
+ --------------------------------------------------------------------------------
110
+
111
+ abbrev mkTargetDecl
112
+ (α) (pkgName «target» : Name)
113
+ [OptDataKind α] [FormatQuery α] [FamilyDef (CustomData pkgName) «target» α]
114
+ (f : NPackage pkgName → FetchM (Job α))
115
+ : TargetDecl :=
116
+ let cfg := mkTargetJobConfig fun pkg => do
117
+ withRegisterJob (pkg.target «target» |>.key.toSimpleString) do
118
+ f pkg
119
+ .mk (.mk pkgName «target» .anonymous (.mk cfg) (by simp [Name.isAnonymous])) rfl
120
+
121
+ @[builtin_macro targetCommand]
122
+ def expandTargetCommand : Macro := fun stx => do
123
+ let `(targetCommand|$(doc?)? $(attrs?)? target%$kw $sig) := stx
124
+ | Macro.throwErrorAt stx "ill-formed target declaration"
125
+ let `(buildDeclSig|$id:ident $[$pkg?]? : $ty := $defn $[$wds?:whereDecls]?) := sig
126
+ | Macro.throwErrorAt sig "ill-formed target signature"
127
+ withRef kw do
128
+ let attr ← `(Term.attrInstance| «target»)
129
+ let attrs := #[attr] ++ expandAttrs attrs?
130
+ let name := Name.quoteFrom id id.getId
131
+ let pkgName := mkIdentFrom id (packageDeclName.str "name")
132
+ let pkg ← expandOptSimpleBinder pkg?
133
+ `(family_def $id : CustomOut ($pkgName, $name) := $ty
134
+ $[$doc?]? abbrev $id :=
135
+ Lake.DSL.mkTargetDecl $ty $pkgName $name (fun $pkg => $defn)
136
+ $[$wds?:whereDecls]?
137
+ @[$attrs,*] def configDecl : ConfigDecl := $(id).toConfigDecl)
138
+
139
+ --------------------------------------------------------------------------------
140
+ /-! ## Lean Library & Executable Target Declarations -/
141
+ --------------------------------------------------------------------------------
142
+
143
+ abbrev mkConfigDecl
144
+ (pkg name kind : Name)
145
+ (config : ConfigType kind pkg name)
146
+ [FamilyDef (CustomData pkg) name (ConfigTarget kind)]
147
+ [FamilyDef DataType kind (ConfigTarget kind)]
148
+ : KConfigDecl kind :=
149
+ {pkg, name, kind, config, wf_data := fun _ => by simp, kind_eq := rfl}
150
+
151
+ def mkConfigDeclDef
152
+ (tyName attr kind : Name)
153
+ [ConfigInfo tyName] [delTyName : TypeName (KConfigDecl kind)]
154
+ (doc? : Option DocComment) (attrs? : Option Attributes)
155
+ (nameStx? : Option IdentOrStr) (cfg : OptConfig)
156
+ : CommandElabM Command := do
157
+ let configId : Ident ← `(config)
158
+ let id ← mkConfigDeclIdent nameStx?
159
+ let name := Name.quoteFrom id id.getId
160
+ let ty := Syntax.mkCApp tyName #[name]
161
+ elabConfig tyName configId ty cfg
162
+ let attrId ← mkIdentFromRef attr
163
+ let targetAttr ← `(Term.attrInstance| «target»)
164
+ let kindAttr ← `(Term.attrInstance| $attrId:ident)
165
+ let attrs := #[targetAttr, kindAttr] ++ expandAttrs attrs?
166
+ let pkg ← mkIdentFromRef (packageDeclName.str "name")
167
+ let declTy ← mkIdentFromRef delTyName.typeName
168
+ let kind := Name.quoteFrom (← getRef) kind
169
+ `(family_def $id : CustomOut ($pkg, $name) := ConfigTarget $kind
170
+ $[$doc?]? abbrev $id : $declTy :=
171
+ Lake.DSL.mkConfigDecl $pkg $name $kind $configId
172
+ @[$attrs,*] def configDecl : ConfigDecl := $(id).toConfigDecl
173
+ )
174
+
175
+ @[builtin_command_elab leanLibCommand]
176
+ def elabLeanLibCommand : CommandElab := fun stx => do
177
+ let `(leanLibCommand|$(doc?)? $(attrs?)? lean_lib%$kw $(nameStx?)? $cfg) := stx
178
+ | throwErrorAt stx "ill-formed lean_lib declaration"
179
+ withRef kw do
180
+ let cmd ← mkConfigDeclDef ``LeanLibConfig LeanLib.keyword LeanLib.configKind doc? attrs? nameStx? cfg
181
+ withMacroExpansion stx cmd <| elabCommand cmd
182
+
183
+ @[inherit_doc leanLibCommand] abbrev LeanLibCommand := TSyntax ``leanLibCommand
184
+
185
+ instance : Coe LeanLibCommand Command where
186
+ coe x := ⟨x.raw⟩
187
+
188
+ @[builtin_command_elab leanExeCommand]
189
+ def elabLeanExeCommand : CommandElab := fun stx => do
190
+ let `(leanExeCommand|$(doc?)? $(attrs?)? lean_exe%$kw $(nameStx?)? $cfg) := stx
191
+ | throwErrorAt stx "ill-formed lean_exe declaration"
192
+ withRef kw do
193
+ let cmd ← mkConfigDeclDef ``LeanExeConfig LeanExe.keyword LeanExe.configKind doc? attrs? nameStx? cfg
194
+ withMacroExpansion stx cmd <| elabCommand cmd
195
+
196
+ @[inherit_doc leanExeCommand] abbrev LeanExeCommand := TSyntax ``leanExeCommand
197
+
198
+ instance : Coe LeanExeCommand Command where
199
+ coe x := ⟨x.raw⟩
200
+
201
+ @[builtin_command_elab inputFileCommand]
202
+ def elabInputfileCommand : CommandElab := fun stx => do
203
+ let `(inputFileCommand|$(doc?)? $(attrs?)? input_file%$kw $(nameStx?)? $cfg) := stx
204
+ | throwErrorAt stx "ill-formed input_file declaration"
205
+ withRef kw do
206
+ let cmd ← mkConfigDeclDef ``InputFileConfig InputFile.keyword InputFile.configKind doc? attrs? nameStx? cfg
207
+ withMacroExpansion stx cmd <| elabCommand cmd
208
+
209
+ @[inherit_doc inputFileCommand] abbrev InputFileCommand := TSyntax ``inputFileCommand
210
+
211
+ instance : Coe InputFileCommand Command where
212
+ coe x := ⟨x.raw⟩
213
+
214
+ @[builtin_command_elab inputDirCommand]
215
+ def elabInputDirCommand : CommandElab := fun stx => do
216
+ let `(inputDirCommand|$(doc?)? $(attrs?)? input_dir%$kw $(nameStx?)? $cfg) := stx
217
+ | throwErrorAt stx "ill-formed input_dir declaration"
218
+ withRef kw do
219
+ let cmd ← mkConfigDeclDef ``InputDirConfig InputDir.keyword InputDir.configKind doc? attrs? nameStx? cfg
220
+ withMacroExpansion stx cmd <| elabCommand cmd
221
+
222
+ @[inherit_doc inputDirCommand] abbrev InputDirCommand := TSyntax ``inputDirCommand
223
+
224
+ instance : Coe InputDirCommand Command where
225
+ coe x := ⟨x.raw⟩
226
+
227
+ --------------------------------------------------------------------------------
228
+ /-! ## External Library Target Declaration -/
229
+ --------------------------------------------------------------------------------
230
+
231
+ abbrev mkExternLibDecl
232
+ (pkgName name : Name)
233
+ [FamilyDef (CustomData pkgName) (.str name "static") FilePath]
234
+ [FamilyDef (CustomData pkgName) name (ConfigTarget ExternLib.configKind)]
235
+ : ExternLibDecl :=
236
+ mkConfigDecl pkgName name ExternLib.configKind {getPath := cast (by simp)}
237
+
238
+ @[builtin_macro externLibCommand]
239
+ def expandExternLibCommand : Macro := fun stx => do
240
+ let `(externLibCommand|$(doc?)? $(attrs?)? extern_lib%$kw $spec) := stx
241
+ | Macro.throwErrorAt stx "ill-formed external library declaration"
242
+ let `(externLibDeclSpec| $nameStx $[$pkg?]? := $defn $[$wds?:whereDecls]?) := spec
243
+ | Macro.throwErrorAt spec "ill-formed external library signature"
244
+ withRef kw do
245
+ let attr1 ← `(Term.attrInstance| «target»)
246
+ let attr2 ← `(Term.attrInstance| «extern_lib»)
247
+ let attrs := #[attr1, attr2] ++ expandAttrs attrs?
248
+ let id := expandIdentOrStrAsIdent nameStx
249
+ let pkgName := mkIdentFrom kw (packageDeclName.str "name")
250
+ let targetId := mkIdentFrom id <| id.getId.modifyBase (· ++ `static)
251
+ let name := Name.quoteFrom id id.getId
252
+ let kind := Name.quoteFrom kw ExternLib.configKind
253
+ `(target $targetId:ident $[$pkg?]? : FilePath := $defn $[$wds?:whereDecls]?
254
+ family_def $id : CustomOut ($pkgName, $name) := ConfigTarget $kind
255
+ $[$doc?:docComment]? def $id : ExternLibDecl :=
256
+ Lake.DSL.mkExternLibDecl $pkgName $name
257
+ @[$attrs,*] def configDecl : ConfigDecl := $(id).toConfigDecl)
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/DSL/VerLit.lean ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Eval
8
+ import Lake.Util.Version
9
+ import Lake.DSL.Syntax
10
+
11
+ open Lean Elab Term Meta
12
+
13
+ /-! # Version Literals
14
+
15
+ Defines the `v!"<ver>"` syntax for version literals.
16
+ The elaborator attempts to synthesize an instance of `DecodeVersion` for the
17
+ expected type and then applies it to the string literal.
18
+ -/
19
+
20
+ namespace Lake
21
+
22
+ instance : ToExpr SemVerCore where
23
+ toExpr ver := mkAppN (mkConst ``SemVerCore.mk)
24
+ #[toExpr ver.major, toExpr ver.minor, toExpr ver.patch]
25
+ toTypeExpr := mkConst ``SemVerCore
26
+
27
+ instance : ToExpr StdVer where
28
+ toExpr ver := mkAppN (mkConst ``StdVer.mk)
29
+ #[toExpr ver.toSemVerCore, toExpr ver.specialDescr]
30
+ toTypeExpr := mkConst ``StdVer
31
+
32
+ private def toResultExpr [ToExpr α] (x : Except String α) : Except String Expr :=
33
+ Functor.map toExpr x
34
+
35
+ @[builtin_term_elab verLit]
36
+ def elabVerLit : TermElab := fun stx expectedType? => do
37
+ let `(v!$v) := stx | throwUnsupportedSyntax
38
+ tryPostponeIfNoneOrMVar expectedType?
39
+ let some expectedType := expectedType?
40
+ | throwError "expected type is not known"
41
+ let ofVerT? ← mkAppM ``Except #[mkConst ``String, expectedType]
42
+ let ofVerE ← elabTermEnsuringType (← ``(decodeVersion s!$v)) ofVerT?
43
+ let resT ← mkAppM ``Except #[mkConst ``String, mkConst ``Expr]
44
+ let resE ← mkAppM ``toResultExpr #[ofVerE]
45
+ match (← unsafe evalExpr (Except String Expr) resT resE) with
46
+ | .ok ver => return ver
47
+ | .error e => throwError e
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Config.lean ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lean.Data.Name
8
+ import Lean.Data.Options
9
+ import Lake.Config.Env
10
+ import Lake.Load.Manifest
11
+ import Lake.Util.FilePath
12
+
13
+ namespace Lake
14
+ open System Lean
15
+
16
+ /-- Context for loading a Lake configuration. -/
17
+ structure LoadConfig where
18
+ /-- The Lake environment of the load process. -/
19
+ lakeEnv : Lake.Env
20
+ /--
21
+ The CLI arguments Lake was run with.
22
+ Used to perform a restart of Lake on a toolchain update.
23
+ A value of `none` means that Lake is not restartable via the CLI.
24
+ -/
25
+ lakeArgs? : Option (Array String) := none
26
+ /-- The absolute path to the root directory of the Lake workspace. -/
27
+ wsDir : FilePath
28
+ /-- The loaded package's directory (relative to the workspace directory). -/
29
+ relPkgDir : FilePath := "."
30
+ /-- The absolute path to the loaded package's directory. -/
31
+ pkgDir : FilePath := wsDir / relPkgDir
32
+ /-- The package's Lake configuration file (relative to its directory). -/
33
+ relConfigFile : FilePath := defaultConfigFile
34
+ /-- The full path to the loaded package's Lake configuration file. -/
35
+ configFile : FilePath := pkgDir / relConfigFile
36
+ /-- Additional package overrides for this workspace load. -/
37
+ packageOverrides : Array PackageEntry := #[]
38
+ /-- A set of key-value Lake configuration options (i.e., `-K` settings). -/
39
+ lakeOpts : NameMap String := {}
40
+ /-- The Lean options with which to elaborate the configuration file. -/
41
+ leanOpts : Options := {}
42
+ /-- Whether Lake should re-elaborate configuration files instead of using cached OLeans. -/
43
+ reconfigure : Bool := false
44
+ /-- Whether to update dependencies when loading the workspace. -/
45
+ updateDeps : Bool := false
46
+ /--
47
+ Whether to update the workspace's `lean-toolchain` when dependencies are updated.
48
+ If `true` and a toolchain update occurs, Lake will need to be restarted.
49
+ -/
50
+ updateToolchain : Bool := true
51
+ /-- The package's scope (e.g., in Reservoir). -/
52
+ scope : String := ""
53
+ /-- The URL to this package's Git remote (if any). -/
54
+ remoteUrl : String := ""
55
+
56
+ /-- The package's Lake directory (for Lake temporary files). -/
57
+ @[inline] def LoadConfig.lakeDir (cfg : LoadConfig) : FilePath :=
58
+ cfg.pkgDir / defaultLakeDir
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Lean.lean ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.Load.Lean.Elab
8
+ import Lake.Load.Lean.Eval
9
+
10
+ /-! # Lean Loader
11
+
12
+ This module contains the main definitions to load a package from a
13
+ Lake configuration file written in Lake's Lean DSL.
14
+ -/
15
+
16
+ open Lean
17
+
18
+ namespace Lake
19
+
20
+ /--
21
+ Elaborate a Lean configuration file into a `Package`.
22
+ The resulting package does not yet include any dependencies.
23
+ -/
24
+ def loadLeanConfig (cfg : LoadConfig)
25
+ : LogIO (Package × Environment) := do
26
+ let configEnv ← importConfigFile cfg
27
+ let {name, config} ← IO.ofExcept <| PackageDecl.loadFromEnv configEnv cfg.leanOpts
28
+ let pkg : Package := {
29
+ name, config
30
+ dir := cfg.pkgDir
31
+ relDir := cfg.relPkgDir
32
+ configFile := cfg.configFile
33
+ relConfigFile := cfg.relConfigFile
34
+ scope := cfg.scope
35
+ remoteUrl := cfg.remoteUrl
36
+ }
37
+ return (← pkg.loadFromEnv configEnv cfg.leanOpts, configEnv)
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Lean/Elab.lean ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Frontend
8
+ import Lake.DSL.Extensions
9
+ import Lake.DSL.Attributes
10
+ import Lake.Load.Config
11
+ import Lake.Build.Trace
12
+ import Lake.Util.Log
13
+
14
+ /-! # Lean Configuration Elaborator
15
+
16
+ This module contains the definitions to elaborate a Lake configuration file.
17
+ -/
18
+
19
+
20
+ open System Lean
21
+
22
+ namespace Lake
23
+
24
+ deriving instance BEq, Hashable for Import
25
+
26
+ /- Cache for the imported header environment of Lake configuration files. -/
27
+ builtin_initialize importEnvCache : IO.Ref (Std.HashMap (Array Import) Environment) ← IO.mkRef {}
28
+
29
+ /-- Like `importModules`, but fetch the resulting import state from the cache if possible. -/
30
+ def importModulesUsingCache (imports : Array Import) (opts : Options) (trustLevel : UInt32) : IO Environment := do
31
+ if let some env := (← importEnvCache.get)[imports]? then
32
+ return env
33
+ let env ← importModules (loadExts := true) imports opts trustLevel
34
+ importEnvCache.modify (·.insert imports env)
35
+ return env
36
+
37
+ /-- Like `Lean.Elab.processHeader`, but using `importEnvCache`. -/
38
+ def processHeader (header : TSyntax ``Parser.Module.header) (opts : Options)
39
+ (inputCtx : Parser.InputContext) : StateT MessageLog IO Environment := do
40
+ try
41
+ let imports := Elab.headerToImports header
42
+ importModulesUsingCache imports opts 1024
43
+ catch e =>
44
+ let pos := inputCtx.fileMap.toPosition <| header.raw.getPos?.getD 0
45
+ modify (·.add { fileName := inputCtx.fileName, data := toString e, pos })
46
+ mkEmptyEnvironment
47
+
48
+ /-- Main module `Name` of a Lake configuration file. -/
49
+ def configModuleName : Name := `lakefile
50
+
51
+ /-- Elaborate `configFile` with the given package directory and options. -/
52
+ def elabConfigFile (pkgDir : FilePath) (lakeOpts : NameMap String)
53
+ (leanOpts := Options.empty) (configFile := pkgDir / defaultLeanConfigFile) : LogIO Environment := do
54
+
55
+ -- Read file and initialize environment
56
+ let input ← IO.FS.readFile configFile
57
+ let inputCtx := Parser.mkInputContext input configFile.toString
58
+ let (header, parserState, messages) ← Parser.parseHeader inputCtx
59
+ let (env, messages) ← processHeader header leanOpts inputCtx messages
60
+ let env := env.setMainModule configModuleName
61
+
62
+ -- Configure extensions
63
+ let env := dirExt.setState env pkgDir
64
+ let env := optsExt.setState env lakeOpts
65
+
66
+ -- Elaborate File
67
+ let commandState := Elab.Command.mkState env messages leanOpts
68
+ let s ← Elab.IO.processCommands inputCtx parserState commandState
69
+
70
+ -- Log messages
71
+ s.commandState.messages.forM (logMessage ·)
72
+
73
+ -- Check result
74
+ if s.commandState.messages.hasErrors then
75
+ error s!"{configFile}: package configuration has errors"
76
+ else
77
+ return s.commandState.env
78
+
79
+ /--
80
+ `Lean.Kernel.Environment.add` is now private, this is an exported helper wrapping it for
81
+ `Lean.Environment`.
82
+ -/
83
+ @[extern "lake_environment_add"]
84
+ private opaque addToEnv (env : Environment) (_ : ConstantInfo) : Environment
85
+
86
+ /--
87
+ Import a configuration `.olean` (e.g., `lakefile.olean`).
88
+ Auxiliary definition for `importConfigFile`.
89
+ -/
90
+ def importConfigFileCore (olean : FilePath) (leanOpts : Options) : IO Environment := do
91
+ /-
92
+ We could import the olean together with its imports using one
93
+ `importModules` call, but that would mean we pay for a full
94
+ `finalizeImports` each time, which is linear in the number of imported
95
+ constants and extension entries (in fact, it is paid two more times: when
96
+ marking the `Environment` object as multi-threaded, and when releasing
97
+ it). As most lakefiles use the same set of imports, we instead construct
98
+ an `Environment` for it only once, and then apply the lakefile contents
99
+ on top of it like the elaborator would. Thus the non-shared part of the
100
+ `Environment` is very small.
101
+ -/
102
+ let (mod, _) ← readModuleData olean
103
+ let env ← importModulesUsingCache mod.imports leanOpts 1024
104
+ -- Apply constants (does not go through the kernel, so order is irrelevant)
105
+ let env := mod.constants.foldl addToEnv env
106
+ /-
107
+ Below, we pass module environment extension entries to
108
+ `PersistentEnvExtension.addEntryFn` - but for an extension of
109
+ non-erased type `PersistentEnvExtension α β σ`, the former are of type
110
+ `α` while `addEntryFn` expects `β`s (the type-erased
111
+ `persistentEnvExtensionsRef` ought to be `unsafe` to prevent this from
112
+ simply compiling but it isn't right now). Fortunately, all extensions
113
+ relevant for workspace loading, which we filter for here, have `α = β`;
114
+ entries for any other extensions can safely be ignored.
115
+ -/
116
+ let extDescrs ← persistentEnvExtensionsRef.get
117
+ let extNameIdx ← mkExtNameMap 0
118
+ let env := mod.entries.foldl (init := env) fun env (extName, ents) =>
119
+ if lakeExts.contains extName then
120
+ match extNameIdx[extName]? with
121
+ | some entryIdx => ents.foldl extDescrs[entryIdx]!.addEntry env
122
+ | none => env
123
+ else
124
+ env
125
+ return env
126
+ where
127
+ lakeExts :=
128
+ NameSet.empty
129
+ -- Lake Persistent Extensions
130
+ |>.insert ``packageAttr
131
+ |>.insert ``packageDepAttr
132
+ |>.insert ``postUpdateAttr
133
+ |>.insert ``scriptAttr
134
+ |>.insert ``defaultScriptAttr
135
+ |>.insert ``leanLibAttr
136
+ |>.insert ``leanExeAttr
137
+ |>.insert ``externLibAttr
138
+ |>.insert ``targetAttr
139
+ |>.insert ``defaultTargetAttr
140
+ |>.insert ``testDriverAttr
141
+ |>.insert ``lintDriverAttr
142
+ |>.insert ``moduleFacetAttr
143
+ |>.insert ``packageFacetAttr
144
+ |>.insert ``libraryFacetAttr
145
+ -- Docstring Extension (e.g., for scripts)
146
+ |>.insert ``docStringExt
147
+ -- IR Extension (for constant evaluation)
148
+ |>.insert ``IR.declMapExt
149
+
150
+ structure ConfigTrace where
151
+ platform : String
152
+ leanHash : String
153
+ configHash : Hash
154
+ options : NameMap String
155
+ deriving ToJson, FromJson
156
+
157
+ /--
158
+ Import the `.olean` for the configuration file if `reconfigure` is not set and
159
+ an up-to-date one exists (i.e., one with matching configuration and on the same
160
+ toolchain). Otherwise, elaborate the configuration and save it to the `.olean`.
161
+ -/
162
+ def importConfigFile (cfg : LoadConfig) : LogIO Environment := do
163
+ let some configName := FilePath.mk <$> cfg.configFile.fileName
164
+ | error "invalid configuration file name"
165
+ let olean := cfg.lakeDir / configName.withExtension "olean"
166
+ let traceFile := cfg.lakeDir / configName.withExtension "olean.trace"
167
+ let lockFile := cfg.lakeDir / configName.withExtension "olean.lock"
168
+ /-
169
+ Remark:
170
+ To prevent race conditions between the `.olean` and its trace file
171
+ (i.e., one process writes a new configuration while another reads an old one
172
+ and vice versa), Lake performs file locking to ensure exclusive access.
173
+
174
+ To check if the trace is up-to-date, Lake opens a read-only handle on the
175
+ trace file and acquires a shared lock on it. The lock is held while the
176
+ trace is read and compared to the expected value. If it matches, the olean is
177
+ imported and the (shared) lock is then released.
178
+
179
+ If the trace is out-of-date, Lake upgrades the trace to read-write handle
180
+ with an exclusive lock. Lake does this by first acquiring a exclusive lock to
181
+ configuration's lock file (i.e. `olean.lock`). While holding this lock, Lake
182
+ releases the shared lock on the trace, re-opens the trace with a read-write
183
+ handle, and acquires an exclusive lock on the trace. It then releases its
184
+ lock on the lock file. writes the new lock data.
185
+ -/
186
+ let acquireTrace h : IO IO.FS.Handle := id do
187
+ let hLock ← IO.FS.Handle.mk lockFile .write
188
+ /-
189
+ Remark:
190
+ We do not wait for a lock here, because that can lead to deadlock.
191
+
192
+ This is because we are already holding a shared lock on the trace.
193
+ If multiple process race for this lock, one will get it and then
194
+ wait for an exclusive lock one the trace file, but be blocked by the
195
+ other process with a shared lock waiting on this file.
196
+
197
+ While there is likely a way to sequence this to avoid erroring,
198
+ simultaneous reconfigures are likely to produce unexpected results
199
+ anyway, so the error seems wise nonetheless.
200
+ -/
201
+ if (← hLock.tryLock) then
202
+ h.unlock
203
+ let h ← IO.FS.Handle.mk traceFile .readWrite
204
+ h.lock
205
+ hLock.unlock
206
+ return h
207
+ else
208
+ h.unlock
209
+ error <| s!"could not acquire an exclusive configuration lock; " ++
210
+ "another process may already be reconfiguring the package"
211
+ let configHash ← computeTextFileHash cfg.configFile
212
+ let elabConfig h (lakeOpts : NameMap String) : LogIO Environment := id do
213
+ /-
214
+ Remark:
215
+ We write the trace before elaborating the configuration file
216
+ to enable automatic reconfiguration on the next `lake` invocation if
217
+ elaboration fails. To ensure a failure triggers a reconfigure, we must also
218
+ remove any previous out-of-date `.olean`. Otherwise, Lake will treat the
219
+ older `.olean` as matching the new trace.
220
+
221
+ See the related PR and Zulip discussion for more details:
222
+ [leanprover/lean4#3069](https://github.com/leanprover/lean4/pull/3069).
223
+ -/
224
+ match (← IO.FS.removeFile olean |>.toBaseIO) with
225
+ | .ok _ | .error (.noFileOrDirectory ..) =>
226
+ h.putStrLn <| Json.pretty <| toJson
227
+ {platform := System.Platform.target, leanHash := cfg.lakeEnv.leanGithash,
228
+ configHash, options := lakeOpts : ConfigTrace}
229
+ h.truncate
230
+ let env ← elabConfigFile cfg.pkgDir lakeOpts cfg.leanOpts cfg.configFile
231
+ Lean.writeModule env olean
232
+ h.unlock
233
+ return env
234
+ | .error e => errorWithLog do
235
+ logError <| toString e
236
+ h.unlock
237
+ IO.FS.removeFile traceFile
238
+ let validateTrace h : LogIO Environment := id do
239
+ if cfg.reconfigure then
240
+ elabConfig (← acquireTrace h) cfg.lakeOpts
241
+ else
242
+ h.lock (exclusive := false)
243
+ let contents ← h.readToEnd
244
+ let .ok (trace : ConfigTrace) := Json.parse contents >>= fromJson?
245
+ | error "compiled configuration is invalid; run with '-R' to reconfigure"
246
+ let upToDate :=
247
+ (← olean.pathExists) ∧ trace.platform = System.Platform.target ∧
248
+ trace.leanHash = cfg.lakeEnv.leanGithash ∧ trace.configHash = configHash
249
+ if upToDate then
250
+ let env ← importConfigFileCore olean cfg.leanOpts
251
+ h.unlock
252
+ return env
253
+ else
254
+ elabConfig (← acquireTrace h) trace.options
255
+ if (← traceFile.pathExists) then
256
+ validateTrace <| ← IO.FS.Handle.mk traceFile .read
257
+ else
258
+ IO.FS.createDirAll cfg.lakeDir
259
+ match (← IO.FS.Handle.mk traceFile .writeNew |>.toBaseIO) with
260
+ | .ok h =>
261
+ h.lock; elabConfig h cfg.lakeOpts
262
+ | .error (.alreadyExists ..) =>
263
+ validateTrace <| ← IO.FS.Handle.mk traceFile .read
264
+ | .error e => error e.toString
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Lean/Eval.lean ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.DSL.Attributes
8
+ import Lake.Config.Workspace
9
+ import Lean.DocString
10
+
11
+ /-! # Lean Configuration Evaluator
12
+
13
+ This module contains the definitions to load Lake configuration objects from
14
+ a Lean environment elaborated from a Lake configuration file.
15
+ -/
16
+
17
+ open System Lean
18
+
19
+ namespace Lake
20
+
21
+ /-- Unsafe implementation of `evalConstCheck`. -/
22
+ unsafe def unsafeEvalConstCheck
23
+ (env : Environment) (opts : Options) (α) [TypeName α] (const : Name)
24
+ : Except String α :=
25
+ match env.find? const with
26
+ | none => throw s!"unknown constant '{const}'"
27
+ | some info =>
28
+ match info.type with
29
+ | Expr.const c _ =>
30
+ if c != TypeName.typeName α then
31
+ throwUnexpectedType
32
+ else
33
+ env.evalConst α opts const
34
+ | _ => throwUnexpectedType
35
+ where
36
+ throwUnexpectedType : Except String α :=
37
+ throw s!"unexpected type at '{const}', `{TypeName.typeName α}` expected"
38
+
39
+ /--
40
+ Like `Lean.Environment.evalConstCheck`,
41
+ but with plain universe-polymorphic `Except`.
42
+ -/
43
+ @[implemented_by unsafeEvalConstCheck]
44
+ opaque evalConstCheck
45
+ (env : Environment) (opts : Options) (α) [TypeName α] (const : Name)
46
+ : Except String α
47
+
48
+ /-- Construct a `DNameMap` from the declarations tagged with `attr`. -/
49
+ def mkTagMap
50
+ (env : Environment) (attr : OrderedTagAttribute)
51
+ [Monad m] (f : (n : Name) → m (β n))
52
+ : m (DNameMap β) :=
53
+ let entries := attr.getAllEntries env
54
+ entries.foldlM (init := {}) fun map declName =>
55
+ return map.insert declName <| ← f declName
56
+
57
+ /-- Construct a `OrdNameMap` from the declarations tagged with `attr`. -/
58
+ def mkOrdTagMap
59
+ (env : Environment) (attr : OrderedTagAttribute)
60
+ [Monad m] (f : (n : Name) → m β)
61
+ : m (OrdNameMap β) :=
62
+ let entries := attr.getAllEntries env
63
+ entries.foldlM (init := .mkEmpty entries.size) fun map declName =>
64
+ return map.insert declName <| ← f declName
65
+
66
+ /-- Load a `PackageDecl` from a configuration environment. -/
67
+ def PackageDecl.loadFromEnv
68
+ (env : Environment) (opts := Options.empty)
69
+ : Except String PackageDecl := do
70
+ let declName ←
71
+ match packageAttr.getAllEntries env |>.toList with
72
+ | [] => error s!"configuration file is missing a `package` declaration"
73
+ | [name] => pure name
74
+ | _ => error s!"configuration file has multiple `package` declarations"
75
+ evalConstCheck env opts _ declName
76
+
77
+ /--
78
+ Load the optional elements of a `Package` from the Lean environment.
79
+ This is done after loading its core configuration but before resolving
80
+ its dependencies.
81
+ -/
82
+ def Package.loadFromEnv
83
+ (self : Package) (env : Environment) (opts : Options)
84
+ : LogIO Package := do
85
+ let strName := self.name.toString (escape := false)
86
+
87
+ -- load target, script, hook, and driver configurations
88
+ let constTargetMap ← IO.ofExcept <| mkOrdTagMap env targetAttr fun name => do
89
+ evalConstCheck env opts ConfigDecl name
90
+ let targetDecls ← constTargetMap.toArray.mapM fun decl => do
91
+ if h : decl.pkg = self.name then
92
+ return .mk decl h
93
+ else
94
+ error s!"\
95
+ target '{decl.name}' was defined in package '{decl.pkg}', \
96
+ but registered under '{self.name}'"
97
+ let targetDeclMap ← targetDecls.foldlM (init := {}) fun m decl => do
98
+ if let some orig := m.find? decl.name then
99
+ error s!"\
100
+ {self.name}: target '{decl.name}' was already defined as a '{orig.kind}', \
101
+ but then redefined as a '{decl.kind}'"
102
+ else
103
+ return m.insert decl.name (.mk decl rfl)
104
+ let defaultTargets ← defaultTargetAttr.getAllEntries env |>.mapM fun name =>
105
+ if let some decl := constTargetMap.find? name then pure decl.name else
106
+ error s!"{self.name}: package is missing target '{name}' marked as a default"
107
+ let scripts ← mkTagMap env scriptAttr fun scriptName => do
108
+ let name := strName ++ "/" ++ scriptName.toString (escape := false)
109
+ let fn ← IO.ofExcept <| evalConstCheck env opts ScriptFn scriptName
110
+ return {name, fn, doc? := ← findDocString? env scriptName : Script}
111
+ let defaultScripts ← defaultScriptAttr.getAllEntries env |>.mapM fun name =>
112
+ if let some script := scripts.find? name then pure script else
113
+ error s!"{self.name}: package is missing script '{name}' marked as a default"
114
+ let postUpdateHooks ← postUpdateAttr.getAllEntries env |>.mapM fun name =>
115
+ match evalConstCheck env opts PostUpdateHookDecl name with
116
+ | .ok decl =>
117
+ if h : decl.pkg = self.name then
118
+ return OpaquePostUpdateHook.mk ⟨h ▸ decl.fn⟩
119
+ else
120
+ error s!"post-update hook was defined in '{decl.pkg}', but was registered in '{self.name}'"
121
+ | .error e => error e
122
+ let depConfigs ← IO.ofExcept <| packageDepAttr.getAllEntries env |>.mapM fun name =>
123
+ evalConstCheck env opts Dependency name
124
+ let testDrivers ← testDriverAttr.getAllEntries env |>.mapM fun name =>
125
+ if let some decl := constTargetMap.find? name then
126
+ pure decl.name
127
+ else if scripts.contains name then
128
+ pure name
129
+ else
130
+ error s!"{self.name}: package is missing script or target '{name}' marked as a test driver"
131
+ let testDriver ←
132
+ if testDrivers.size > 1 then
133
+ error s!"{self.name}: only one script, executable, or library can be tagged @[test_driver]"
134
+ else if h : testDrivers.size > 0 then
135
+ if self.config.testDriver.isEmpty then
136
+ pure (testDrivers[0]'h |>.toString)
137
+ else
138
+ error s!"{self.name}: cannot both set testDriver and use @[test_driver]"
139
+ else
140
+ pure self.config.testDriver
141
+ let lintDrivers ← lintDriverAttr.getAllEntries env |>.mapM fun name =>
142
+ if let some decl := constTargetMap.find? name then
143
+ pure decl.name
144
+ else if scripts.contains name then
145
+ pure name
146
+ else
147
+ error s!"{self.name}: package is missing script or target '{name}' marked as a lint driver"
148
+ let lintDriver ←
149
+ if lintDrivers.size > 1 then
150
+ error s!"{self.name}: only one script or executable can be tagged @[lint_driver]"
151
+ else if h : lintDrivers.size > 0 then
152
+ if self.config.lintDriver.isEmpty then
153
+ pure (lintDrivers[0]'h |>.toString)
154
+ else
155
+ error s!"{self.name}: cannot both set lintDriver and use @[lint_driver]"
156
+ else
157
+ pure self.config.lintDriver
158
+
159
+ -- Deprecation warnings
160
+ unless self.config.manifestFile.isNone do
161
+ logWarning s!"{self.name}: package configuration option 'manifestFile' is deprecated"
162
+
163
+ -- Fill in the Package
164
+ return {self with
165
+ depConfigs, targetDecls, targetDeclMap
166
+ defaultTargets, scripts, defaultScripts
167
+ testDriver, lintDriver, postUpdateHooks
168
+ }
169
+
170
+ /--
171
+ Load module/package facets into a `Workspace` from a configuration environment.
172
+ -/
173
+ def Workspace.addFacetsFromEnv
174
+ (env : Environment) (opts : Options) (self : Workspace)
175
+ : Except String Workspace := do
176
+ let mut ws := self
177
+ for name in moduleFacetAttr.getAllEntries env do
178
+ let decl ← evalConstCheck env opts ModuleFacetDecl name
179
+ ws := ws.addModuleFacetConfig decl.config
180
+ for name in packageFacetAttr.getAllEntries env do
181
+ let decl ← evalConstCheck env opts PackageFacetDecl name
182
+ ws := ws.addPackageFacetConfig decl.config
183
+ for name in libraryFacetAttr.getAllEntries env do
184
+ let decl ← evalConstCheck env opts LibraryFacetDecl name
185
+ ws := ws.addLibraryFacetConfig decl.config
186
+ return ws
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Manifest.lean ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone, Gabriel Ebner
5
+ -/
6
+ prelude
7
+ import Lake.Util.Log
8
+ import Lake.Util.Name
9
+ import Lake.Util.FilePath
10
+ import Lake.Util.JsonObject
11
+ import Lake.Util.Version
12
+ import Lake.Config.Defaults
13
+
14
+ open System Lean
15
+
16
+ /-! # Lake Manifest
17
+ The data structure of a Lake manifest and the definitions needed
18
+ to create, modify, serialize, and deserialize it.
19
+ -/
20
+
21
+ namespace Lake
22
+
23
+ /--
24
+ The current version of the manifest format.
25
+
26
+ Three-part semantic versions were introduced in `v1.0.0`.
27
+ Major version increments indicate breaking changes
28
+ (e.g., new required fields and semantic changes to existing fields).
29
+ Minor version increments (after `0.x`) indicate backwards-compatible extensions
30
+ (e.g., adding optional fields, removing fields).
31
+
32
+ Lake supports reading manifests with versions that have `-` suffixes.
33
+ When checking for version compatibility, Lake expects a manifest with version
34
+ `x.y.z-foo` to have all the features of the official manifest version `x.y.z`.
35
+ That is, Lake ignores the `-` suffix.
36
+
37
+ **VERSION HISTORY**
38
+
39
+ **v0.x.0** (versioned by a natural number)
40
+ - `1`: First version
41
+ - `2`: Adds optional `inputRev` package entry field
42
+ - `3`: Changes entry to inductive (with `path`/`git`)
43
+ - `4`: Adds required `packagesDir` manifest field
44
+ - `5`: Adds optional `inherited` package entry field (and removed `opts`)
45
+ - `6`: Adds optional package root `name` manifest field
46
+ - `7`: `type` refactor, custom to/fromJson
47
+
48
+ **v1.x.x** (versioned by a string)
49
+ - `"1.0.0"`: Switches to a semantic versioning scheme
50
+ - `"1.1.0"`: Add optional `scope` package entry field
51
+ -/
52
+ @[inline] def Manifest.version : StdVer := {major := 1, minor := 1}
53
+
54
+ /-- Manifest version `0.6.0` package entry. For backwards compatibility. -/
55
+ inductive PackageEntryV6
56
+ | path (name : Name) (opts : NameMap String) (inherited : Bool) (dir : FilePath)
57
+ | git (name : Name) (opts : NameMap String) (inherited : Bool) (url : String) (rev : String)
58
+ (inputRev? : Option String) (subDir? : Option FilePath)
59
+ deriving FromJson, ToJson, Inhabited
60
+
61
+ /--
62
+ The package source for an entry in the manifest.
63
+ Describes exactly how Lake should materialize the package.
64
+ -/
65
+ inductive PackageEntrySrc
66
+ /--
67
+ A local filesystem package. `dir` is relative to the package directory
68
+ of the package containing the manifest.
69
+ -/
70
+ | path
71
+ (dir : FilePath)
72
+ /-- A remote Git package. -/
73
+ | git
74
+ (url : String)
75
+ (rev : String)
76
+ (inputRev? : Option String)
77
+ (subDir? : Option FilePath)
78
+ deriving Inhabited
79
+
80
+ /-- An entry for a package stored in the manifest. -/
81
+ structure PackageEntry where
82
+ name : Name
83
+ scope : String := ""
84
+ inherited : Bool
85
+ configFile : FilePath := defaultConfigFile
86
+ manifestFile? : Option FilePath := none
87
+ src : PackageEntrySrc
88
+ deriving Inhabited
89
+
90
+ namespace PackageEntry
91
+
92
+ protected def toJson (entry : PackageEntry) : Json :=
93
+ let fields := [
94
+ ("name", toJson entry.name),
95
+ ("scope", toJson entry.scope),
96
+ ("configFile" , toJson entry.configFile),
97
+ ("manifestFile", toJson entry.manifestFile?),
98
+ ("inherited", toJson entry.inherited),
99
+ ]
100
+ let fields :=
101
+ match entry.src with
102
+ | .path dir =>
103
+ ("type", "path") :: fields.append [
104
+ ("dir", toJson dir),
105
+ ]
106
+ | .git url rev inputRev? subDir? =>
107
+ ("type", "git") :: fields.append [
108
+ ("url", toJson url),
109
+ ("rev", toJson rev),
110
+ ("inputRev", toJson inputRev?),
111
+ ("subDir", toJson subDir?),
112
+ ]
113
+ Json.mkObj fields
114
+
115
+ instance : ToJson PackageEntry := ⟨PackageEntry.toJson⟩
116
+
117
+ protected def fromJson? (json : Json) : Except String PackageEntry := do
118
+ let obj ← JsonObject.fromJson? json |>.mapError (s!"package entry: {·}")
119
+ let name ← obj.get "name" |>.mapError (s!"package entry: {·}")
120
+ let scope ← obj.getD "scope" ""
121
+ try
122
+ let type ← obj.get "type"
123
+ let inherited ← obj.get "inherited"
124
+ let configFile ← obj.getD "configFile" defaultConfigFile
125
+ let manifestFile ← obj.getD "manifestFile" defaultManifestFile
126
+ let src : PackageEntrySrc ← id do
127
+ match type with
128
+ | "path" =>
129
+ let dir ← obj.get "dir"
130
+ return .path dir
131
+ | "git" =>
132
+ let url ← obj.get "url"
133
+ let rev ← obj.get "rev"
134
+ let inputRev? ← obj.get? "inputRev"
135
+ let subDir? ← obj.get? "subDir"
136
+ return .git url rev inputRev? subDir?
137
+ | _ =>
138
+ throw s!"unknown package entry type '{type}'"
139
+ return {
140
+ name, scope, inherited,
141
+ configFile, manifestFile? := manifestFile, src
142
+ : PackageEntry
143
+ }
144
+ catch e =>
145
+ throw s!"package entry '{name}': {e}"
146
+
147
+ instance : FromJson PackageEntry := ⟨PackageEntry.fromJson?⟩
148
+
149
+ @[inline] def setInherited (entry : PackageEntry) : PackageEntry :=
150
+ {entry with inherited := true}
151
+
152
+ @[inline] def setConfigFile (path : FilePath) (entry : PackageEntry) : PackageEntry :=
153
+ {entry with configFile := path}
154
+
155
+ @[inline] def setManifestFile (path? : Option FilePath) (entry : PackageEntry) : PackageEntry :=
156
+ {entry with manifestFile? := path?}
157
+
158
+ @[inline] def inDirectory (pkgDir : FilePath) (entry : PackageEntry) : PackageEntry :=
159
+ {entry with src := match entry.src with | .path dir => .path (pkgDir / dir) | s => s}
160
+
161
+ def ofV6 : PackageEntryV6 → PackageEntry
162
+ | .path name _opts inherited dir =>
163
+ {name, inherited, src := .path dir}
164
+ | .git name _opts inherited url rev inputRev? subDir? =>
165
+ {name, inherited, src := .git url rev inputRev? subDir?}
166
+
167
+ end PackageEntry
168
+
169
+ /-- Manifest data structure that is serialized to the file. -/
170
+ structure Manifest where
171
+ name : Name
172
+ lakeDir : FilePath
173
+ packagesDir? : Option FilePath := none
174
+ packages : Array PackageEntry := #[]
175
+
176
+ namespace Manifest
177
+
178
+ /-- Add a package entry to the end of a manifest. -/
179
+ def addPackage (entry : PackageEntry) (self : Manifest) : Manifest :=
180
+ {self with packages := self.packages.push entry}
181
+
182
+ protected def toJson (self : Manifest) : Json :=
183
+ Json.mkObj [
184
+ ("version", toJson version),
185
+ ("name", toJson self.name),
186
+ ("lakeDir", toJson self.lakeDir),
187
+ ("packagesDir", toJson self.packagesDir?),
188
+ ("packages", toJson self.packages),
189
+ ]
190
+
191
+ instance : ToJson Manifest := ⟨Manifest.toJson⟩
192
+
193
+ def getVersion (obj : JsonObject) : Except String SemVerCore := do
194
+ let ver : Json ← obj.get "version" <|> obj.get "schemaVersion"
195
+ let ver : SemVerCore ←
196
+ match ver with
197
+ | (n : Nat) => pure {minor := n}
198
+ | (s : String) => StdVer.parse s
199
+ | ver => throw s!"invalid version '{ver}'; \
200
+ you may need to update your 'lean-toolchain'"
201
+ if ver.major > 1 then
202
+ throw s!"schema version '{ver}' is of a higher major version than this \
203
+ Lake's '{Manifest.version}'; you may need to update your 'lean-toolchain'"
204
+ else if ver < {minor := 5} then
205
+ throw s!"incompatible manifest version '{ver}'"
206
+ else
207
+ return ver
208
+
209
+ def getPackages (ver : StdVer) (obj : JsonObject) : Except String (Array PackageEntry) := do
210
+ if ver < {minor := 7} then
211
+ (·.map PackageEntry.ofV6) <$> obj.getD "packages" #[]
212
+ else
213
+ obj.getD "packages" #[]
214
+
215
+ protected def fromJson? (json : Json) : Except String Manifest := do
216
+ let obj ← JsonObject.fromJson? json
217
+ let ver ← getVersion obj
218
+ let name ← obj.getD "name" Name.anonymous
219
+ let lakeDir ← obj.getD "lakeDir" defaultLakeDir
220
+ let packagesDir? ← obj.get? "packagesDir"
221
+ let packages ← getPackages ver obj
222
+ return {name, lakeDir, packagesDir?, packages}
223
+
224
+ instance : FromJson Manifest := ⟨Manifest.fromJson?⟩
225
+
226
+ /-- Parse a `Manifest` from a string. -/
227
+ def parse (data : String) : Except String Manifest := do
228
+ match Json.parse data with
229
+ | .ok json => fromJson? json
230
+ | .error e => throw s!"invalid JSON: {e}"
231
+
232
+ /-- Parse a manifest file. -/
233
+ def load (file : FilePath) : IO Manifest := do
234
+ let contents ← IO.FS.readFile file
235
+ match inline <| Manifest.parse contents with
236
+ | .ok a => return a
237
+ | .error e => error s!"{file}: {e}"
238
+
239
+ /--
240
+ Parse a manifest file. Returns `none` if the file does not exist.
241
+ Errors if the manifest is ill-formatted or the read files for other reasons.
242
+ -/
243
+ def load? (file : FilePath) : IO (Option Manifest) := do
244
+ match (← inline (load file) |>.toBaseIO) with
245
+ | .ok contents => return contents
246
+ | .error (.noFileOrDirectory ..) => return none
247
+ | .error e => throw e
248
+
249
+ /-- Serialize the manifest to a JSON file. -/
250
+ def save (self : Manifest) (manifestFile : FilePath) : IO PUnit := do
251
+ let contents := Json.pretty self.toJson
252
+ IO.FS.writeFile manifestFile <| contents.push '\n'
253
+
254
+ @[deprecated save (since := "2024-12-17")] abbrev saveToFile := @save
255
+
256
+ /-- Deserialize package entries from a (partial) JSON manifest. -/
257
+ def decodeEntries (data : Json) : Except String (Array PackageEntry) := do
258
+ let obj ← JsonObject.fromJson? data
259
+ getPackages (← getVersion obj) obj
260
+
261
+ /-- Deserialize manifest package entries from a JSON string. -/
262
+ def parseEntries (data : String) : Except String (Array PackageEntry) := do
263
+ match Json.parse data with
264
+ | .ok json => decodeEntries json
265
+ | .error e => throw s!"invalid JSON: {e}"
266
+
267
+ /-- Deserialize manifest package entries from a JSON file. -/
268
+ def loadEntries (file : FilePath) : IO (Array PackageEntry) := do
269
+ let contents ← IO.FS.readFile file
270
+ match inline <| parseEntries contents with
271
+ | .ok a => return a
272
+ | .error e => error s!"{file}: {e}"
273
+
274
+ /--
275
+ Deserialize manifest package entries from a JSON file.
276
+ Returns an empty array if the file does not exist.
277
+ -/
278
+ def tryLoadEntries (file : FilePath) : IO (Array PackageEntry) := do
279
+ match (← inline (loadEntries file) |>.toBaseIO) with
280
+ | .ok a => return a
281
+ | .error (.noFileOrDirectory ..) => return #[]
282
+ | .error e => error s!"{file}: {e}"
283
+
284
+ /-- Serialize manifest package entries to a JSON file. -/
285
+ def saveEntries (file : FilePath) (entries : Array PackageEntry) : IO PUnit := do
286
+ let contents := Json.pretty <| Json.mkObj [
287
+ ("schemaVersion", toJson version),
288
+ ("packages", toJson entries)
289
+ ]
290
+ IO.FS.writeFile file <| contents.push '\n'
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Materialize.lean ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2017 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Gabriel Ebner, Sebastian Ullrich, Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.Util.Git
8
+ import Lake.Load.Manifest
9
+ import Lake.Config.Dependency
10
+ import Lake.Config.Package
11
+ import Lake.Reservoir
12
+
13
+ open System Lean
14
+
15
+ /-! # Dependency Materialization
16
+ Definitions to "materialize" a package dependency.
17
+ That is, clone a local copy of a Git dependency at a specific revision
18
+ or resolve a local path dependency.
19
+ -/
20
+
21
+ namespace Lake
22
+
23
+ /-- Update the Git package in `repo` to `rev` if not already at it. -/
24
+ def updateGitPkg
25
+ (name : String) (repo : GitRepo) (rev? : Option String)
26
+ : LogIO PUnit := do
27
+ let rev ← repo.findRemoteRevision rev?
28
+ if (← repo.getHeadRevision) = rev then
29
+ if (← repo.hasDiff) then
30
+ logWarning s!"{name}: repository '{repo.dir}' has local changes"
31
+ else
32
+ logInfo s!"{name}: checking out revision '{rev}'"
33
+ repo.checkoutDetach rev
34
+
35
+ /-- Clone the Git package as `repo`. -/
36
+ def cloneGitPkg
37
+ (name : String) (repo : GitRepo) (url : String) (rev? : Option String)
38
+ : LogIO PUnit := do
39
+ logInfo s!"{name}: cloning {url}"
40
+ repo.clone url
41
+ if let some rev := rev? then
42
+ let rev ← repo.resolveRemoteRevision rev
43
+ logInfo s!"{name}: checking out revision '{rev}'"
44
+ repo.checkoutDetach rev
45
+
46
+ /--
47
+ Update the Git repository from `url` in `repo` to `rev?`.
48
+ If `repo` is already from `url`, just checkout the new revision.
49
+ Otherwise, delete the local repository and clone a fresh copy from `url`.
50
+ -/
51
+ def updateGitRepo
52
+ (name : String) (repo : GitRepo) (url : String) (rev? : Option String)
53
+ : LogIO Unit := do
54
+ let sameUrl ← EIO.catchExceptions (h := fun _ => pure false) <| show IO Bool from do
55
+ let some remoteUrl ← repo.getRemoteUrl? | return false
56
+ if remoteUrl = url then return true
57
+ return (← IO.FS.realPath remoteUrl) = (← IO.FS.realPath url)
58
+ if sameUrl then
59
+ updateGitPkg name repo rev?
60
+ else
61
+ if System.Platform.isWindows then
62
+ -- Deleting git repositories via IO.FS.removeDirAll does not work reliably on windows
63
+ logInfo s!"{name}: URL has changed; you might need to delete '{repo.dir}' manually"
64
+ updateGitPkg name repo rev?
65
+ else
66
+ logInfo s!"{name}: URL has changed; deleting '{repo.dir}' and cloning again"
67
+ IO.FS.removeDirAll repo.dir
68
+ cloneGitPkg name repo url rev?
69
+
70
+ /--
71
+ Materialize the Git repository from `url` into `repo` at `rev?`.
72
+ Clone it if no local copy exists, otherwise update it.
73
+ -/
74
+ def materializeGitRepo
75
+ (name : String) (repo : GitRepo) (url : String) (rev? : Option String)
76
+ : LogIO Unit := do
77
+ if (← repo.dirExists) then
78
+ updateGitRepo name repo url rev?
79
+ else
80
+ cloneGitPkg name repo url rev?
81
+
82
+ structure MaterializedDep where
83
+ /-- Path to the materialized package relative to the workspace's root directory. -/
84
+ relPkgDir : FilePath
85
+ /--
86
+ URL for the materialized package.
87
+ Used as the endpoint from which to fetch cloud releases for the package.
88
+ -/
89
+ remoteUrl : String
90
+ /-- The manifest entry for the dependency. -/
91
+ manifestEntry : PackageEntry
92
+ deriving Inhabited
93
+
94
+ @[inline] def MaterializedDep.name (self : MaterializedDep) :=
95
+ self.manifestEntry.name
96
+
97
+ @[inline] def MaterializedDep.scope (self : MaterializedDep) :=
98
+ self.manifestEntry.scope
99
+
100
+ /-- Path to the dependency's configuration file (relative to `relPkgDir`). -/
101
+ @[inline] def MaterializedDep.manifestFile? (self : MaterializedDep) :=
102
+ self.manifestEntry.manifestFile?
103
+
104
+ /-- Path to the dependency's configuration file (relative to `relPkgDir`). -/
105
+ @[inline] def MaterializedDep.configFile (self : MaterializedDep) :=
106
+ self.manifestEntry.configFile
107
+
108
+ def pkgNotIndexed (scope name : String) (rev? : Option String := none) : String :=
109
+ let (leanRev, tomlRev) :=
110
+ if let some rev := rev? then
111
+ (s!" @ {repr rev}", s! "\n rev = {repr rev}")
112
+ else ("", "")
113
+ s!"{scope}/{name}: package not found on Reservoir.
114
+
115
+ If the package is on GitHub, you can add a Git source. For example:
116
+
117
+ require ...
118
+ from git \"https://github.com/{scope}/{name}\"{leanRev}
119
+
120
+ or, if using TOML:
121
+
122
+ [[require]]
123
+ git = \"https://github.com/{scope}/{name}\"{tomlRev}
124
+ ...
125
+ "
126
+
127
+ /--
128
+ Materializes a configuration dependency.
129
+ For Git dependencies, updates it to the latest input revision.
130
+ -/
131
+ def Dependency.materialize
132
+ (dep : Dependency) (inherited : Bool)
133
+ (lakeEnv : Env) (wsDir relPkgsDir relParentDir : FilePath)
134
+ : LogIO MaterializedDep := do
135
+ if let some src := dep.src? then
136
+ match src with
137
+ | .path dir =>
138
+ let relPkgDir := relParentDir / dir
139
+ return mkDep relPkgDir "" (.path relPkgDir)
140
+ | .git url inputRev? subDir? => do
141
+ let sname := dep.name.toString (escape := false)
142
+ let repoUrl := Git.filterUrl? url |>.getD ""
143
+ materializeGit sname (relPkgsDir / sname) url repoUrl inputRev? subDir?
144
+ else
145
+ if dep.scope.isEmpty then
146
+ error s!"{dep.name}: ill-formed dependency: \
147
+ dependency is missing a source and is missing a scope for Reservoir"
148
+ let verRev? ← dep.version?.mapM fun ver =>
149
+ if ver.startsWith "git#" then
150
+ return ver.drop 4
151
+ else
152
+ error s!"{dep.name}: unsupported dependency version format '{ver}' (should be \"git#<rev>\")"
153
+ let depName := dep.name.toString (escape := false)
154
+ let pkg ←
155
+ match (← Reservoir.fetchPkg? lakeEnv dep.scope depName |>.toLogT) with
156
+ | .ok (some pkg) => pure pkg
157
+ | .ok none => error <| pkgNotIndexed dep.scope depName verRev?
158
+ | .error e =>
159
+ logError s!"{dep.scope}/{depName}: could not materialize package: \
160
+ this may be a transient error or a bug in Lake or Reservoir"
161
+ throw e
162
+ let relPkgDir := relPkgsDir / pkg.name
163
+ match pkg.gitSrc? with
164
+ | some (.git _ url githubUrl? defaultBranch? subDir?) =>
165
+ materializeGit pkg.fullName relPkgDir url
166
+ (githubUrl?.getD "") (verRev? <|> defaultBranch?) subDir?
167
+ | _ => error s!"{pkg.fullName}: Git source not found on Reservoir"
168
+ where
169
+ materializeGit name relPkgDir gitUrl remoteUrl inputRev? subDir? : LogIO MaterializedDep := do
170
+ let repo := GitRepo.mk (wsDir / relPkgDir)
171
+ let gitUrl := lakeEnv.pkgUrlMap.find? dep.name |>.getD gitUrl
172
+ materializeGitRepo name repo gitUrl inputRev?
173
+ let rev ← repo.getHeadRevision
174
+ let relPkgDir := if let some subDir := subDir? then relPkgDir / subDir else relPkgDir
175
+ return mkDep relPkgDir remoteUrl <| .git gitUrl rev inputRev? subDir?
176
+ @[inline] mkDep relPkgDir remoteUrl src : MaterializedDep := {
177
+ relPkgDir, remoteUrl,
178
+ manifestEntry := {name := dep.name, scope := dep.scope, inherited, src}
179
+ }
180
+
181
+ /--
182
+ Materializes a manifest package entry, cloning and/or checking it out as necessary.
183
+ -/
184
+ def PackageEntry.materialize
185
+ (manifestEntry : PackageEntry)
186
+ (lakeEnv : Env) (wsDir relPkgsDir : FilePath)
187
+ : LogIO MaterializedDep :=
188
+ match manifestEntry.src with
189
+ | .path (dir := relPkgDir) .. =>
190
+ return mkDep relPkgDir ""
191
+ | .git (url := url) (rev := rev) (subDir? := subDir?) .. => do
192
+ let sname := manifestEntry.name.toString (escape := false)
193
+ let relGitDir := relPkgsDir / sname
194
+ let gitDir := wsDir / relGitDir
195
+ let repo := GitRepo.mk gitDir
196
+ /-
197
+ Do not update (fetch remote) if already on revision
198
+ Avoids errors when offline, e.g., [leanprover/lake#104][104].
199
+
200
+ [104]: https://github.com/leanprover/lake/issues/104
201
+ -/
202
+ if (← repo.dirExists) then
203
+ if (← repo.getHeadRevision?) = rev then
204
+ if (← repo.hasDiff) then
205
+ logWarning s!"{sname}: repository '{repo.dir}' has local changes"
206
+ else
207
+ let url := lakeEnv.pkgUrlMap.find? manifestEntry.name |>.getD url
208
+ updateGitRepo sname repo url rev
209
+ else
210
+ let url := lakeEnv.pkgUrlMap.find? manifestEntry.name |>.getD url
211
+ cloneGitPkg sname repo url rev
212
+ let relPkgDir := match subDir? with | .some subDir => relGitDir / subDir | .none => relGitDir
213
+ return mkDep relPkgDir (Git.filterUrl? url |>.getD "")
214
+ where
215
+ @[inline] mkDep relPkgDir remoteUrl : MaterializedDep :=
216
+ {relPkgDir, remoteUrl, manifestEntry}
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Package.lean ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.Load.Lean
8
+ import Lake.Load.Toml
9
+
10
+ /-! # Package Loader
11
+
12
+ This module contains the main definitions to load a package
13
+ from Lake configuration file (either Lean or TOML).
14
+ -/
15
+
16
+ open Lean
17
+
18
+ namespace Lake
19
+ open System (FilePath)
20
+
21
+ /--
22
+ Return whether a configuration file with the given name
23
+ and/or a supported extension exists.
24
+ -/
25
+ def configFileExists (cfgFile : FilePath) : BaseIO Bool :=
26
+ if cfgFile.extension.isSome then
27
+ cfgFile.pathExists
28
+ else
29
+ let leanFile := cfgFile.addExtension "lean"
30
+ let tomlFile := cfgFile.addExtension "toml"
31
+ leanFile.pathExists <||> tomlFile.pathExists
32
+
33
+ /--
34
+ Returns the normalized real path of the configuration file (if it exists).
35
+ Otherwise, returns an empty string.
36
+ -/
37
+ def realConfigFile (cfgFile : FilePath) : BaseIO FilePath := do
38
+ if cfgFile.extension.isSome then
39
+ resolvePath cfgFile
40
+ else
41
+ if let some path ← resolvePath? (cfgFile.addExtension "lean") then
42
+ return path
43
+ else
44
+ resolvePath (cfgFile.addExtension "toml")
45
+
46
+ /--
47
+ Loads a Lake package configuration (either Lean or TOML).
48
+ The resulting package does not yet include any dependencies.
49
+ -/
50
+ def loadPackageCore
51
+ (name : String) (cfg : LoadConfig)
52
+ : LogIO (Package × Option Environment) := do
53
+ if let some ext := cfg.relConfigFile.extension then
54
+ let cfg ←
55
+ if let some configFile ← resolvePath? cfg.configFile then
56
+ pure {cfg with configFile}
57
+ else error s!"{name}: configuration file not found: {cfg.configFile}"
58
+ match ext with
59
+ | "lean" => (·.map id some) <$> loadLeanConfig cfg
60
+ | "toml" => ((·,none)) <$> loadTomlConfig cfg
61
+ | _ => error s!"{name}: configuration has unsupported file extension: {cfg.configFile}"
62
+ else
63
+ let relLeanFile := cfg.relConfigFile.addExtension "lean"
64
+ let relTomlFile := cfg.relConfigFile.addExtension "toml"
65
+ let leanFile := cfg.pkgDir / relLeanFile
66
+ let tomlFile := cfg.pkgDir / relTomlFile
67
+ if let some configFile ← resolvePath? leanFile then
68
+ if (← tomlFile.pathExists) then
69
+ logInfo s!"{name}: {relLeanFile} and {relTomlFile} are both present; using {relLeanFile}"
70
+ let cfg := {cfg with configFile, relConfigFile := relLeanFile}
71
+ let (pkg, env) ← loadLeanConfig cfg
72
+ return (pkg, some env)
73
+ else
74
+ if let some configFile ← resolvePath? tomlFile then
75
+ let cfg := {cfg with configFile, relConfigFile := relTomlFile}
76
+ let pkg ← loadTomlConfig cfg
77
+ return (pkg, none)
78
+ else
79
+ error s!"{name}: no configuration file with a supported extension:\n{leanFile}\n{tomlFile}"
80
+
81
+ /-- Loads a Lake package as a single independent object (without dependencies). -/
82
+ def loadPackage (config : LoadConfig) : LogIO Package := do
83
+ Lean.searchPathRef.set config.lakeEnv.leanSearchPath
84
+ (·.1) <$> loadPackageCore "[root]" config
85
+
86
+ /-- Load the package's input-to-content mapping from the Lake cache (if enabled). -/
87
+ protected def Package.loadInputsFrom (env : Env) (pkg : Package) : LogIO Package := do
88
+ if env.lakeCache.isDisabled || !(pkg.enableArtifactCache?.getD env.enableArtifactCache) then
89
+ return pkg
90
+ else
91
+ let inputs ← CacheMap.load (pkg.inputsFileIn env.lakeCache)
92
+ return {pkg with cacheRef? := ← IO.mkRef inputs}
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Resolve.lean ADDED
@@ -0,0 +1,471 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone, Gabriel Ebner
5
+ -/
6
+ prelude
7
+ import Lake.Config.Monad
8
+ import Lake.Util.StoreInsts
9
+ import Lake.Build.Topological
10
+ import Lake.Load.Materialize
11
+ import Lake.Load.Package
12
+
13
+ open System Lean
14
+
15
+ /-! # Dependency Resolution
16
+
17
+ This module contains definitions for resolving the dependencies of a package.
18
+ -/
19
+
20
+ namespace Lake
21
+
22
+ def stdMismatchError (newName : String) (rev : String) :=
23
+ s!"the 'std' package has been renamed to '{newName}' and moved to the
24
+ 'leanprover-community' organization; downstream packages which wish to
25
+ update to the new std should replace
26
+
27
+ require std from
28
+ git \"https://github.com/leanprover/std4\"{rev}
29
+
30
+ in their Lake configuration file with
31
+
32
+ require {newName} from
33
+ git \"https://github.com/leanprover-community/{newName}\"{rev}
34
+ "
35
+
36
+ /--
37
+ Loads the package configuration of a materialized dependency.
38
+ Adds the facets defined in the package to the `Workspace`.
39
+ -/
40
+ def loadDepPackage
41
+ (dep : MaterializedDep)
42
+ (lakeOpts : NameMap String)
43
+ (leanOpts : Options) (reconfigure : Bool)
44
+ : StateT Workspace LogIO Package := fun ws => do
45
+ let name := dep.name.toString (escape := false)
46
+ let pkgDir := ws.dir / dep.relPkgDir
47
+ let some pkgDir ← resolvePath? pkgDir
48
+ | error s!"{name}: package directory not found: {pkgDir}"
49
+ let (pkg, env?) ← loadPackageCore name {
50
+ lakeEnv := ws.lakeEnv
51
+ wsDir := ws.dir
52
+ pkgDir
53
+ relPkgDir := dep.relPkgDir
54
+ relConfigFile := dep.configFile
55
+ lakeOpts, leanOpts, reconfigure
56
+ scope := dep.scope
57
+ remoteUrl := dep.remoteUrl
58
+ }
59
+ let pkg ← pkg.loadInputsFrom ws.lakeEnv
60
+ if let some env := env? then
61
+ let ws ← IO.ofExcept <| ws.addFacetsFromEnv env leanOpts
62
+ return (pkg, ws)
63
+ else
64
+ return (pkg, ws)
65
+
66
+ /--
67
+ The resolver's call stack of dependencies.
68
+ That is, the dependency currently being resolved plus its parents.
69
+ -/
70
+ abbrev DepStack := CallStack Name
71
+
72
+ /--
73
+ A monad transformer for recursive dependency resolution.
74
+ It equips the monad with the stack of dependencies currently being resolved.
75
+ -/
76
+ abbrev DepStackT m := CallStackT Name m
77
+
78
+ @[inline] nonrec def DepStackT.run
79
+ (x : DepStackT m α) (stack : DepStack := {})
80
+ : m α :=
81
+ x.run stack
82
+
83
+ /-- Log dependency cycle and error. -/
84
+ @[specialize] def depCycleError [MonadError m] (cycle : Cycle Name) : m α :=
85
+ error s!"dependency cycle detected:\n{formatCycle cycle}"
86
+
87
+ instance [Monad m] [MonadError m] : MonadCycleOf Name (DepStackT m) where
88
+ throwCycle := depCycleError
89
+
90
+ /-- The monad of the dependency resolver. -/
91
+ abbrev ResolveT m := DepStackT <| StateT Workspace m
92
+
93
+ @[inline] nonrec def ResolveT.run
94
+ (ws : Workspace) (x : ResolveT m α) (stack : DepStack := {})
95
+ : m (α × Workspace) :=
96
+ x.run stack |>.run ws
97
+
98
+ /-- Recursively run a `ResolveT` monad starting from the workspace's root. -/
99
+ @[specialize] private def Workspace.runResolveT
100
+ [Monad m] [MonadError m] (ws : Workspace)
101
+ (go : RecFetchFn Package PUnit (ResolveT m))
102
+ (root := ws.root) (stack : DepStack := {})
103
+ : m Workspace := do
104
+ let (_, ws) ← ResolveT.run ws (stack := stack) do
105
+ inline <| recFetchAcyclic (·.name) go root
106
+ return ws
107
+
108
+ /-
109
+ Recursively visits each node in a package's dependency graph, starting from
110
+ the workspace package `root`. Each dependency missing from the workspace is
111
+ resolved using the `resolve` function and added into the workspace.
112
+
113
+ Recursion occurs breadth-first. Each direct dependency of a package is
114
+ resolved in reverse order before recursing to the dependencies' dependencies.
115
+
116
+ See `Workspace.updateAndMaterializeCore` for more details.
117
+ -/
118
+ @[inline] private def Workspace.resolveDepsCore
119
+ [Monad m] [MonadError m] (ws : Workspace)
120
+ (load : Package → Dependency → StateT Workspace m Package)
121
+ (root : Package := ws.root) (stack : DepStack := {})
122
+ : m Workspace := do
123
+ ws.runResolveT go root stack
124
+ where
125
+ @[specialize] go pkg recurse : ResolveT m Unit := do
126
+ let start := (← getWorkspace).packages.size
127
+ -- Materialize and load the missing direct dependencies of `pkg`
128
+ pkg.depConfigs.forRevM fun dep => do
129
+ let ws ← getWorkspace
130
+ if ws.packageMap.contains dep.name then
131
+ return -- already handled in another branch
132
+ if pkg.name = dep.name then
133
+ error s!"{pkg.name}: package requires itself (or a package with the same name)"
134
+ let depPkg ← load pkg dep
135
+ modifyThe Workspace (·.addPackage depPkg)
136
+ -- Recursively load the dependencies' dependencies
137
+ (← getWorkspace).packages.forM recurse start
138
+
139
+ /--
140
+ Adds monad state used to update the manifest.
141
+ It equips the monad with a map of locked dependencies.
142
+ -/
143
+ abbrev UpdateT := StateT (NameMap PackageEntry)
144
+
145
+ @[inline] nonrec def UpdateT.run (x : UpdateT m α) (init : NameMap PackageEntry := {}) : m (α × NameMap PackageEntry) :=
146
+ x.run init
147
+
148
+ /--
149
+ Reuse manifest versions of root packages that should not be updated.
150
+ Also, move the packages directory if its location has changed.
151
+ -/
152
+ private def reuseManifest
153
+ (ws : Workspace) (toUpdate : NameSet)
154
+ : UpdateT LoggerIO PUnit := do
155
+ let rootName := ws.root.name.toString (escape := false)
156
+ match (← Manifest.load ws.manifestFile |>.toBaseIO) with
157
+ | .ok manifest =>
158
+ -- Reuse manifest versions
159
+ unless toUpdate.isEmpty do
160
+ manifest.packages.forM fun entry => do
161
+ unless entry.inherited || toUpdate.contains entry.name do
162
+ store entry.name entry
163
+ -- Move packages directory
164
+ if let some oldRelPkgsDir := manifest.packagesDir? then
165
+ let oldPkgsDir := ws.dir / oldRelPkgsDir
166
+ if oldRelPkgsDir.normalize != ws.relPkgsDir.normalize && (← oldPkgsDir.pathExists) then
167
+ logInfo s!"workspace packages directory changed; \
168
+ renaming '{oldPkgsDir}' to '{ws.pkgsDir}'"
169
+ let doRename : IO Unit := do
170
+ createParentDirs ws.pkgsDir
171
+ IO.FS.rename oldPkgsDir ws.pkgsDir
172
+ if let .error e ← doRename.toBaseIO then
173
+ error s!"could not rename workspace packages directory: {e}"
174
+ | .error (.noFileOrDirectory ..) =>
175
+ logInfo s!"{rootName}: no previous manifest, creating one from scratch"
176
+ | .error e =>
177
+ unless toUpdate.isEmpty do
178
+ liftM (m := IO) <| throw e -- only ignore manifest on a bare `lake update`
179
+ logWarning s!"{rootName}: ignoring previous manifest because it failed to load: {e}"
180
+
181
+ /-- Add a package dependency's manifest entries to the update state. -/
182
+ private def addDependencyEntries (pkg : Package) : UpdateT LoggerIO PUnit := do
183
+ match (← Manifest.load pkg.manifestFile |>.toBaseIO) with
184
+ | .ok manifest =>
185
+ manifest.packages.forM fun entry => do
186
+ unless (← getThe (NameMap PackageEntry)).contains entry.name do
187
+ let entry := entry.setInherited.inDirectory pkg.relDir
188
+ store entry.name entry
189
+ | .error (.noFileOrDirectory ..) =>
190
+ logWarning s!"{pkg.name}: ignoring missing manifest '{pkg.manifestFile}'"
191
+ | .error e =>
192
+ logWarning s!"{pkg.name}: ignoring manifest because it failed to load: {e}"
193
+
194
+ /-- Materialize a single dependency, updating it if desired. -/
195
+ private def updateAndMaterializeDep
196
+ (ws : Workspace) (pkg : Package) (dep : Dependency)
197
+ : UpdateT LoggerIO MaterializedDep := do
198
+ if let some entry ← fetch? dep.name then
199
+ entry.materialize ws.lakeEnv ws.dir ws.relPkgsDir
200
+ else
201
+ let inherited := pkg.name ≠ ws.root.name
202
+ /-
203
+ NOTE: A path dependency inherited from another dependency's manifest
204
+ will always be of the form a `./<relPath>` (i.e., be relative to its
205
+ workspace). Thus, when relativized to this workspace, it will have the
206
+ path `<relPkgDir>/./<relPath>`. However, if defining dependency lacks
207
+ a manifest, it will instead be locked as `<relPkgDir>/<relPath>`.
208
+ Adding a `.` here eliminates this difference.
209
+ -/
210
+ let relPkgDir := if pkg.relDir == "." then pkg.relDir else pkg.relDir / "."
211
+ let matDep ← dep.materialize inherited ws.lakeEnv ws.dir ws.relPkgsDir relPkgDir
212
+ store matDep.name matDep.manifestEntry
213
+ return matDep
214
+
215
+ /-- Verify that a dependency was loaded with the correct name. -/
216
+ private def validateDep
217
+ (pkg : Package) (dep : Dependency) (matDep : MaterializedDep) (depPkg : Package)
218
+ : LoggerIO PUnit := do
219
+ if depPkg.name ≠ dep.name then
220
+ if dep.name = .mkSimple "std" then
221
+ let rev :=
222
+ match matDep.manifestEntry.src with
223
+ | .git (inputRev? := some rev) .. => s!" @ {repr rev}"
224
+ | _ => ""
225
+ logError (stdMismatchError depPkg.name.toString rev)
226
+ if matDep.manifestEntry.src matches .git .. then
227
+ if let .error e ← IO.FS.removeDirAll depPkg.dir |>.toBaseIO then -- cleanup
228
+ -- Deleting git repositories via IO.FS.removeDirAll does not work reliably on Windows
229
+ logError s!"'{dep.name}' was downloaded incorrectly; \
230
+ you will need to manually delete '{depPkg.dir}': {e}"
231
+ error s!"{pkg.name}: package '{depPkg.name}' was required as '{dep.name}'"
232
+
233
+ /--
234
+ Exit code returned if Lake needs a manual restart.
235
+ Used, for instance, if the toolchain is updated and no Elan is detected.
236
+ -/
237
+ def restartCode : ExitCode := 4
238
+
239
+ /--
240
+ Update the workspace's `lean-toolchain` if necessary.
241
+
242
+ Compares the root's toolchain with that of its direct dependencies to find the
243
+ best match. If none can be found, issue warning and return normally. If an
244
+ update is found
245
+ -/
246
+ def Workspace.updateToolchain
247
+ (ws : Workspace) (rootDeps : Array MaterializedDep)
248
+ : LoggerIO PUnit := do
249
+ let rootToolchainFile := ws.root.dir / toolchainFileName
250
+ let rootTc? ← ToolchainVer.ofDir? ws.dir
251
+ let (src, tc?, tcs) ← rootDeps.foldlM (init := (ws.root.name, rootTc?, #[])) fun s dep => do
252
+ let depTc? ← ToolchainVer.ofDir? (ws.dir / dep.relPkgDir)
253
+ let some depTc := depTc?
254
+ | return s
255
+ let (src, tc?, tcs) := s
256
+ let some tc := tc?
257
+ | return (dep.name, depTc?, tcs)
258
+ if depTc ≤ tc then
259
+ return (src, tc, tcs)
260
+ else if tc < depTc then
261
+ return (dep.name, depTc, tcs)
262
+ else
263
+ return (src, tc, tcs.push (dep.name, depTc))
264
+ if 0 < tcs.size then
265
+ let s := "toolchain not updated; multiple toolchain candidates:"
266
+ let s := if let some tc := tc? then s!"{s}\n {tc}\n from {src}" else s
267
+ let s := tcs.foldl (init := s) fun s (d, tc) => s!"{s}\n {tc}\n from {d}"
268
+ logWarning s
269
+ else if let some tc := tc? then
270
+ if rootTc?.any (· == tc) then
271
+ logInfo "toolchain not updated; already up-to-date"
272
+ return
273
+ logInfo s!"updating toolchain to '{tc}'"
274
+ IO.FS.writeFile rootToolchainFile tc.toString
275
+ let some lakeArgs := ws.lakeArgs?
276
+ | logInfo s!"cannot auto-restart; you will need to manually restart Lake"
277
+ IO.Process.exit restartCode.toUInt8
278
+ let some elanInstall := ws.lakeEnv.elan?
279
+ | logInfo s!"no Elan detected; you will need to manually restart Lake"
280
+ IO.Process.exit restartCode.toUInt8
281
+ logInfo s!"restarting Lake via Elan"
282
+ let child ← IO.Process.spawn {
283
+ cmd := elanInstall.elan.toString
284
+ args := #["run", "--install", tc.toString, "lake"] ++ lakeArgs
285
+ env := Env.noToolchainVars
286
+ }
287
+ IO.Process.exit (← child.wait).toUInt8
288
+ else
289
+ logInfo s!"toolchain not updated; no toolchain information found"
290
+
291
+ /--
292
+ Updates the workspace, materializing and reconfiguring dependencies.
293
+
294
+ Dependencies are updated to latest specific revision matching that in `require`
295
+ (e.g., if the `require` is `@master`, update to latest commit on master) or
296
+ removed if the `require` is removed.
297
+ If `tuUpdate` is empty, all direct dependencies of the workspace's root will be
298
+ updated and/or remove. Otherwise, only those specified will be updated.
299
+
300
+ If `updateToolchain := true`, the workspace's toolchain is also updated to the
301
+ latest toolchain compatible with the root and its direct dependencies.
302
+ If there are multiple incomparable toolchain versions across them,
303
+ a warning will be issued and no update performed.
304
+ If an update is performed, Lake will automatically restart the update on the new
305
+ toolchain (via `elan`). If `elan` is missing, it will instead request a manual
306
+ restart from the user and exit immediately with `restartCode`.
307
+
308
+ **Dependency Traversal Order**
309
+
310
+ All dependencies of a package are visited in reverse order before recursing
311
+ to the dependencies' dependencies. For example, given the dependency graph:
312
+
313
+ ```
314
+ R
315
+ |- A
316
+ |- B
317
+ |- X
318
+ |- Y
319
+ |- C
320
+ ```
321
+
322
+ Lake follows the order `R`, `C`, `B`, `A`, `Y`, `X`.
323
+
324
+ The reason for this is two-fold:
325
+ 1. Like targets, later requires should shadow earlier definitions.
326
+ 2. Requires written by a user should take priority over those inherited
327
+ from dependencies.
328
+
329
+ Were Lake to use a depth-first traversal, for example, Lake would follow
330
+ the order `R`, `A`, `B`, `X`, `Y`, `C`. If `X` and `C` are both the package
331
+ `foo`, Lake would use the configuration of `foo` found in `B` rather than in
332
+ the root `R`, which would likely confuse the user.
333
+ -/
334
+ def Workspace.updateAndMaterializeCore
335
+ (ws : Workspace)
336
+ (toUpdate : NameSet := {}) (leanOpts : Options := {})
337
+ (updateToolchain := true)
338
+ : LoggerIO (Workspace × NameMap PackageEntry) := UpdateT.run do
339
+ reuseManifest ws toUpdate
340
+ let ws := ws.addPackage ws.root
341
+ if updateToolchain then
342
+ let deps := ws.root.depConfigs.reverse
343
+ let matDeps ← deps.mapM fun dep => do
344
+ logVerbose s!"{ws.root.name}: updating '{dep.name}' with {toJson dep.opts}"
345
+ updateAndMaterializeDep ws ws.root dep
346
+ ws.updateToolchain matDeps
347
+ let start := ws.packages.size
348
+ let ws ← (deps.zip matDeps).foldlM (init := ws) fun ws (dep, matDep) => do
349
+ let (depPkg, ws) ← loadUpdatedDep ws.root dep matDep ws
350
+ let ws := ws.addPackage depPkg
351
+ return ws
352
+ ws.packages.foldlM (init := ws) (start := start) fun ws pkg =>
353
+ ws.resolveDepsCore (stack := [ws.root.name]) updateAndLoadDep pkg
354
+ else
355
+ ws.resolveDepsCore updateAndLoadDep
356
+ where
357
+ @[inline] updateAndLoadDep pkg dep := do
358
+ let matDep ← updateAndMaterializeDep (← getWorkspace) pkg dep
359
+ loadUpdatedDep pkg dep matDep
360
+ @[inline] loadUpdatedDep pkg dep matDep : StateT Workspace (UpdateT LoggerIO) Package := do
361
+ let depPkg ← loadDepPackage matDep dep.opts leanOpts true
362
+ validateDep pkg dep matDep depPkg
363
+ addDependencyEntries depPkg
364
+ return depPkg
365
+
366
+ /-- Write package entries to the workspace manifest. -/
367
+ def Workspace.writeManifest
368
+ (ws : Workspace) (entries : NameMap PackageEntry)
369
+ : IO PUnit := do
370
+ let manifestEntries := ws.packages.foldl (init := #[]) fun arr pkg =>
371
+ match entries.find? pkg.name with
372
+ | some entry => arr.push <|
373
+ entry.setManifestFile pkg.relManifestFile |>.setConfigFile pkg.relConfigFile
374
+ | none => arr -- should only be the case for the root
375
+ let manifest : Manifest := {
376
+ name := ws.root.name
377
+ lakeDir := ws.relLakeDir
378
+ packagesDir? := ws.relPkgsDir
379
+ packages := manifestEntries
380
+ }
381
+ manifest.save ws.manifestFile
382
+
383
+ /-- Run a package's `post_update` hooks. -/
384
+ def Package.runPostUpdateHooks (pkg : Package) : LakeT LoggerIO PUnit := do
385
+ unless pkg.postUpdateHooks.isEmpty do
386
+ logInfo s!"{pkg.name}: running post-update hooks"
387
+ pkg.postUpdateHooks.forM fun hook => hook.get.fn pkg
388
+
389
+ /--
390
+ Updates the workspace, writes the new Lake manifest, and runs package
391
+ post-update hooks.
392
+
393
+ See `Workspace.updateAndMaterializeCore` for details on the update process.
394
+ -/
395
+ def Workspace.updateAndMaterialize
396
+ (ws : Workspace)
397
+ (toUpdate : NameSet := {}) (leanOpts : Options := {})
398
+ (updateToolchain := true)
399
+ : LoggerIO Workspace := do
400
+ let (ws, entries) ←
401
+ ws.updateAndMaterializeCore toUpdate leanOpts updateToolchain
402
+ ws.writeManifest entries
403
+ ws.runLakeT do ws.packages.forM (·.runPostUpdateHooks)
404
+ return ws
405
+
406
+ /--
407
+ Check whether entries in the manifest are up-to-date,
408
+ reporting warnings and/or errors as appropriate.
409
+ -/
410
+ def validateManifest
411
+ (pkgEntries : NameMap PackageEntry) (deps : Array Dependency)
412
+ : LoggerIO PUnit := do
413
+ deps.forM fun dep => do
414
+ let warnOutOfDate (what : String) :=
415
+ logWarning <|
416
+ s!"manifest out of date: {what} of dependency '{dep.name}' changed; \
417
+ use `lake update {dep.name}` to update it"
418
+ let some src := dep.src? | return
419
+ let some entry := pkgEntries.find? dep.name | return
420
+ match src, entry.src with
421
+ | .git (url := url) (rev := rev) .., .git (url := url') (inputRev? := rev') .. =>
422
+ if url ≠ url' then warnOutOfDate "git url"
423
+ if rev ≠ rev' then warnOutOfDate "git revision"
424
+ | .path .., .path .. => pure ()
425
+ | _, _ => warnOutOfDate "source kind (git/path)"
426
+
427
+ /--
428
+ Resolving a workspace's dependencies using a manifest,
429
+ downloading and/or updating them as necessary.
430
+ -/
431
+ def Workspace.materializeDeps
432
+ (ws : Workspace) (manifest : Manifest)
433
+ (leanOpts : Options := {}) (reconfigure := false)
434
+ (overrides : Array PackageEntry := #[])
435
+ : LoggerIO Workspace := do
436
+ -- Load locked dependencies
437
+ if !manifest.packages.isEmpty && manifest.packagesDir? != some (mkRelPathString ws.relPkgsDir) then
438
+ logWarning <|
439
+ "manifest out of date: packages directory changed; \
440
+ use `lake update` to rebuild the manifest \
441
+ (warning: this will update ALL workspace dependencies)"
442
+ let relPkgsDir := manifest.packagesDir?.getD ws.relPkgsDir
443
+ let mut pkgEntries := mkNameMap PackageEntry
444
+ pkgEntries := manifest.packages.foldl (init := pkgEntries) fun map entry =>
445
+ map.insert entry.name entry
446
+ validateManifest pkgEntries ws.root.depConfigs
447
+ let wsOverrides ← Manifest.tryLoadEntries ws.packageOverridesFile
448
+ pkgEntries := wsOverrides.foldl (init := pkgEntries) fun map entry =>
449
+ map.insert entry.name entry
450
+ pkgEntries := overrides.foldl (init := pkgEntries) fun map entry =>
451
+ map.insert entry.name entry
452
+ if pkgEntries.isEmpty && !ws.root.depConfigs.isEmpty then
453
+ error "missing manifest; use `lake update` to generate one"
454
+ -- Materialize all dependencies
455
+ let ws := ws.addPackage ws.root
456
+ ws.resolveDepsCore fun pkg dep => do
457
+ let ws ← getWorkspace
458
+ if let some entry := pkgEntries.find? dep.name then
459
+ let result ← entry.materialize ws.lakeEnv ws.dir relPkgsDir
460
+ loadDepPackage result dep.opts leanOpts reconfigure
461
+ else
462
+ if pkg.name = ws.root.name then
463
+ error <|
464
+ s!"dependency '{dep.name}' not in manifest; \
465
+ use `lake update {dep.name}` to add it"
466
+ else
467
+ error <|
468
+ s!"dependency '{dep.name}' of '{pkg.name}' not in manifest; \
469
+ this suggests that the manifest is corrupt; \
470
+ use `lake update` to generate a new, complete file \
471
+ (warning: this will update ALL workspace dependencies)"
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Toml.lean ADDED
@@ -0,0 +1,450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.Toml.Load
8
+ import Lake.Toml.Decode
9
+ import Lake.Config.Package
10
+ import Lake.Util.Log
11
+
12
+ open Lean Parser
13
+ open System (FilePath)
14
+
15
+ /-! # TOML Loader
16
+
17
+ This module contains the main definitions to load a package from a
18
+ Lake configuration file written in TOML.
19
+ -/
20
+
21
+ namespace Lake
22
+
23
+ open Toml
24
+
25
+ /-! ## General Helpers -/
26
+
27
+ @[specialize] def decodeFieldCore
28
+ (name : Name) (decode : Toml.Value → EDecodeM α) [field : ConfigField σ name α]
29
+ (_ : Table) (val : Value) (cfg : σ)
30
+ : DecodeM σ := fun es =>
31
+ match decode val es with
32
+ | .ok a es => .ok (field.set a cfg) es
33
+ | .error _ es => .ok cfg es
34
+
35
+ class DecodeField (σ : Type) (name : Name) where
36
+ decodeField (t : Table) (val : Value) (cfg : σ) : DecodeM σ
37
+
38
+ export DecodeField (decodeField)
39
+
40
+ instance [DecodeToml α] [ConfigField σ name α] : DecodeField σ name where
41
+ decodeField := decodeFieldCore name decodeToml
42
+
43
+ structure TomlFieldInfo (σ : Type) where
44
+ decodeAndSet : Table → Value → σ → DecodeM σ
45
+
46
+ abbrev TomlFieldInfos (σ : Type) :=
47
+ NameMap (TomlFieldInfo σ)
48
+
49
+ def TomlFieldInfos.empty : TomlFieldInfos σ := {}
50
+
51
+ @[inline] def TomlFieldInfos.insert
52
+ (name : Name) [DecodeField σ name] (infos : TomlFieldInfos σ)
53
+ : TomlFieldInfos σ :=
54
+ NameMap.insert infos name ⟨decodeField name⟩
55
+
56
+ class ConfigTomlInfo (α : Type) where
57
+ fieldInfos : TomlFieldInfos α
58
+
59
+ def Toml.Table.decodeConfig
60
+ [EmptyCollection α] [ConfigTomlInfo α] (t : Table)
61
+ : Toml.DecodeM α :=
62
+ t.foldM (init := {}) fun cfg key val => do
63
+ if let some info := ConfigTomlInfo.fieldInfos.find? key then
64
+ info.decodeAndSet t val cfg
65
+ else
66
+ return cfg
67
+
68
+ @[inline] def decodeTableValue (decode : Table → DecodeM α) (v : Value) : EDecodeM α := do
69
+ ensureDecode <| decode (← v.decodeTable)
70
+
71
+ /-! ## Value Decoders -/
72
+
73
+ def takeNamePart (ss : Substring) (pre : Name) : (Substring × Name) :=
74
+ if ss.isEmpty then
75
+ (ss, .anonymous)
76
+ else
77
+ let curr := ss.front
78
+ if isIdBeginEscape curr then
79
+ let ss := ss.drop 1
80
+ let startPos := ss.startPos
81
+ let ss := ss.dropWhile (!isIdEndEscape ·)
82
+ if isIdEndEscape ss.front then
83
+ let id := ss.str.extract startPos ss.startPos
84
+ (ss, Name.str pre id)
85
+ else
86
+ (ss, .anonymous)
87
+ else if isIdFirst curr then
88
+ let startPos := ss.startPos
89
+ let ss := ss.drop 1 |>.dropWhile isIdRest
90
+ let id := ss.str.extract startPos ss.startPos
91
+ (ss, Name.str pre id)
92
+ else if curr.isDigit then
93
+ let startPos := ss.startPos
94
+ let ss := ss.drop 1 |>.dropWhile Char.isDigit
95
+ let digits := ss.str.extract startPos ss.startPos
96
+ let n := (Syntax.decodeNatLitVal? digits).get!
97
+ (ss, Name.num pre n)
98
+ else
99
+ (ss, .anonymous)
100
+
101
+ partial def takeName (ss : Substring) : (Substring × Name) :=
102
+ let rec takeRest ss pre :=
103
+ if ss.front == '.' then
104
+ let startPos := ss.startPos
105
+ let (ss, n) := takeNamePart (ss.drop 1) pre
106
+ if n.isAnonymous then ({ss with startPos}, pre) else takeRest ss n
107
+ else
108
+ (ss, pre)
109
+ let (ss, n) := takeNamePart ss .anonymous
110
+ if n.isAnonymous then (ss, .anonymous) else takeRest ss n
111
+
112
+ def Glob.ofString? (v : String) : Option Glob := do
113
+ let (ss, n) := takeName v.toSubstring
114
+ if n.isAnonymous then failure
115
+ if h : ss.str.atEnd ss.startPos then
116
+ return .one n
117
+ else if ss.str.get' ss.startPos h == '.' then
118
+ match (ss.drop 1).front with
119
+ | '+' => return .submodules n
120
+ | '*' => return .andSubmodules n
121
+ | _ => failure
122
+ else
123
+ failure
124
+
125
+ protected def Glob.decodeToml (v : Value) : EDecodeM Glob := do
126
+ match inline <| Glob.ofString? (← v.decodeString) with
127
+ | some v => return v
128
+ | none => throwDecodeErrorAt v.ref "expected glob"
129
+
130
+ instance : DecodeToml Glob := ⟨Glob.decodeToml⟩
131
+ instance : DecodeToml (Array Glob) := ⟨Value.decodeArrayOrSingleton⟩
132
+
133
+ protected def LeanOptionValue.decodeToml : Value → EDecodeM LeanOptionValue
134
+ | .string _ v => return .ofString v
135
+ | .boolean _ v => return .ofBool v
136
+ | .integer _ (.ofNat v) => return .ofNat v
137
+ | x => throwDecodeErrorAt x.ref "expected string, boolean, or nonnegative integer"
138
+
139
+ instance : DecodeToml LeanOptionValue := ⟨LeanOptionValue.decodeToml⟩
140
+
141
+ protected def LeanOption.decodeToml (v : Value) : EDecodeM LeanOption := do
142
+ match v with
143
+ | .array ref vs =>
144
+ if h : vs.size = 2 then ensureDecode do
145
+ let name : Name ← tryDecode <| decodeToml vs[0]
146
+ let value ← tryDecode <| decodeToml vs[1]
147
+ return {name, value}
148
+ else
149
+ throwDecodeErrorAt ref "expected array of size 2"
150
+ | .table ref t => ensureDecode do
151
+ let name ← t.tryDecode `name ref
152
+ let value ← t.tryDecode `value ref
153
+ return {name, value}
154
+ | v =>
155
+ throwDecodeErrorAt v.ref "expected array or table"
156
+
157
+ instance : DecodeToml LeanOption := ⟨LeanOption.decodeToml⟩
158
+
159
+ protected def BuildType.decodeToml (v : Value) : EDecodeM BuildType := do
160
+ match inline <| BuildType.ofString? (← v.decodeString) with
161
+ | some v => return v
162
+ | none => throwDecodeErrorAt v.ref "expected one of 'debug', 'relWithDebInfo', 'minSizeRel', 'release'"
163
+
164
+ instance : DecodeToml BuildType := ⟨(BuildType.decodeToml ·)⟩
165
+
166
+ protected def Backend.decodeToml (v : Value) : EDecodeM Backend := do
167
+ match inline <| Backend.ofString? (← v.decodeString) with
168
+ | some v => return v
169
+ | none => throwDecodeErrorAt v.ref "expected one of 'c', 'llvm', or 'default'"
170
+
171
+ instance : DecodeToml Backend := ⟨Backend.decodeToml⟩
172
+
173
+ partial def decodeLeanOptionsAux
174
+ (v : Value) (k : Name) (vs : EDecodeM (Array LeanOption))
175
+ : EDecodeM (Array LeanOption) :=
176
+ match v with
177
+ | .table _ t => t.items.foldl (init := vs) fun vs (k',v) =>
178
+ decodeLeanOptionsAux v (k ++ k') vs
179
+ | v => mergeErrors vs (decodeToml v) fun vs v => vs.push ⟨k,v⟩
180
+
181
+ def decodeLeanOptions (v : Value) : EDecodeM (Array LeanOption) :=
182
+ match v with
183
+ | .array _ vs => decodeArray vs
184
+ | .table _ t => t.items.foldl (init := .ok #[]) fun vs (k,v) => decodeLeanOptionsAux v k vs
185
+ | v => throwDecodeErrorAt v.ref "expected array or table"
186
+
187
+ instance : DecodeToml (Array LeanOption) := ⟨decodeLeanOptions⟩
188
+
189
+ protected def StdVer.decodeToml (v : Value) : EDecodeM LeanVer := do
190
+ match StdVer.parse (← v.decodeString) with
191
+ | .ok v => return v
192
+ | .error e => throwDecodeErrorAt v.ref e
193
+
194
+ instance : DecodeToml StdVer := ⟨StdVer.decodeToml⟩
195
+
196
+ mutual
197
+
198
+ partial def Pattern.decodeToml
199
+ [IsPattern β α] [DecodeToml β] (v : Value) (presets : NameMap (Pattern α β) := {})
200
+ : EDecodeM (Pattern α β) :=
201
+ have : DecodeToml (PatternDescr α β) := ⟨PatternDescr.decodeToml⟩
202
+ match v with
203
+ | .string _ s =>
204
+ if s == "*" then
205
+ return .star
206
+ else
207
+ .ofDescr <$> decodeToml v
208
+ | .table r t => do
209
+ if let some name ← t.decode? `preset then
210
+ if let some preset := presets.find? name then
211
+ return preset
212
+ else
213
+ throwDecodeErrorAt r s!"unknown preset '{name}'"
214
+ else
215
+ .ofDescr <$> decodeToml v
216
+ | v => .ofDescr <$> decodeToml v
217
+
218
+ partial def PatternDescr.decodeToml
219
+ [IsPattern β α] [DecodeToml β] (v : Value)
220
+ : EDecodeM (PatternDescr α β) :=
221
+ have : DecodeToml (Pattern α β) := ⟨Pattern.decodeToml⟩
222
+ match v with
223
+ | .table _ t => do
224
+ if let some p ← t.decode? `not then
225
+ return .not p
226
+ if let some p ← t.decode? `any then
227
+ return .any p
228
+ else if let some p ← t.decode? `all then
229
+ return .all p
230
+ else
231
+ .coe <$> decodeToml v
232
+ | v => .coe <$> decodeToml v
233
+
234
+ end
235
+
236
+ instance [IsPattern β α] [DecodeToml β] : DecodeToml (Pattern α β) := ⟨Pattern.decodeToml⟩
237
+ instance [IsPattern β α] [DecodeToml β] : DecodeToml (PatternDescr α β) := ⟨PatternDescr.decodeToml⟩
238
+
239
+ protected def StrPatDescr.decodeToml (v : Value) : EDecodeM StrPatDescr :=
240
+ match v with
241
+ | .array _ vs => .mem <$> decodeArray vs
242
+ | .table r t => do
243
+ if let some affix ← t.decode? `startsWith then
244
+ return .startsWith affix
245
+ else if let some affix ← t.decode? `endsWith then
246
+ return .endsWith affix
247
+ else
248
+ throwDecodeErrorAt r "expected string pattern"
249
+ | v => throwDecodeErrorAt v.ref "expected string pattern"
250
+
251
+ instance : DecodeToml StrPatDescr := ⟨StrPatDescr.decodeToml⟩
252
+
253
+ protected def PathPatDescr.decodeToml (v : Value) : EDecodeM PathPatDescr :=
254
+ match v with
255
+ | .table r t => do
256
+ if let some p ← t.decode? `path then
257
+ return .path p
258
+ else if let some p ← t.decode? `extension then
259
+ return .extension p
260
+ else if let some p ← t.decode? `fileName then
261
+ return .fileName p
262
+ else
263
+ throwDecodeErrorAt r "expected file path pattern"
264
+ | v => throwDecodeErrorAt v.ref "expected file path pattern"
265
+
266
+ instance : DecodeToml PathPatDescr := ⟨PathPatDescr.decodeToml⟩
267
+
268
+ def decodeVersionTags (v : Value) : EDecodeM StrPat :=
269
+ inline <| Pattern.decodeToml (presets := versionTagPresets) v
270
+
271
+ instance : DecodeField (PackageConfig n) `versionTags where
272
+ decodeField := decodeFieldCore `versionTags decodeVersionTags
273
+
274
+ -- for `platformIndependent`, `releaseRepo`, `buildArchive`, etc.
275
+ instance [DecodeToml α] : DecodeToml (Option α) := ⟨(some <$> decodeToml ·)⟩
276
+
277
+ def PartialBuildKey.decodeToml (v : Value) : EDecodeM PartialBuildKey := do
278
+ match PartialBuildKey.parse (← v.decodeString) with
279
+ | .ok k => return k
280
+ | .error e => throwDecodeErrorAt v.ref e
281
+
282
+ instance : DecodeToml PartialBuildKey := ⟨PartialBuildKey.decodeToml⟩
283
+ instance : DecodeToml (Target α) := ⟨(Target.mk <$> PartialBuildKey.decodeToml ·)⟩
284
+
285
+ def decodeFacets (kind : Name) (val : Value) : EDecodeM (Array Name) := do
286
+ return (← val.decodeArray).map (kind ++ ·)
287
+
288
+ instance : DecodeField (LeanLibConfig n) `defaultFacets where
289
+ decodeField := decodeFieldCore `defaultFacets (decodeFacets LeanLib.facetKind)
290
+
291
+ -- HACK to work around the fact the TOML decoders
292
+ -- do not support inter-field dependencies by default
293
+ def decodeRoots
294
+ (t : Table) (v : Value) (cfg : LeanLibConfig n)
295
+ : DecodeM (LeanLibConfig n) := do
296
+ let cfg ← decodeField `roots t v cfg
297
+ if t.contains `globs then
298
+ return cfg
299
+ else
300
+ return {cfg with globs := mkFieldDefault `globs cfg}
301
+
302
+ instance : DecodeField (LeanLibConfig n) `roots := ⟨decodeRoots⟩
303
+
304
+ /-! ## Dependency Configuration Decoders -/
305
+
306
+ protected def DependencySrc.decodeToml (t : Table) (ref := Syntax.missing) : EDecodeM DependencySrc := do
307
+ let typeVal ← t.decodeValue `type
308
+ match (← typeVal.decodeString) with
309
+ | "path" =>
310
+ return .path (← t.decode `dir)
311
+ | "git" => ensureDecode do
312
+ return .git (← t.tryDecode `url ref) (← t.tryDecode? `rev) (← t.tryDecode? `subDir)
313
+ | _ =>
314
+ throwDecodeErrorAt typeVal.ref "expected one of 'path' or 'git'"
315
+
316
+ instance : DecodeToml DependencySrc := ⟨fun v => do DependencySrc.decodeToml (← v.decodeTable) v.ref⟩
317
+
318
+ protected def Dependency.decodeToml (t : Table) (ref := Syntax.missing) : EDecodeM Dependency := ensureDecode do
319
+ let name ← stringToLegalOrSimpleName <$> t.tryDecode `name ref
320
+ let rev? ← t.tryDecode? `rev
321
+ let src? : Option DependencySrc ← id do
322
+ if let some dir ← t.tryDecode? `path then
323
+ return some <| .path dir
324
+ else if let some g := t.find? `git then
325
+ match g with
326
+ | .string _ url =>
327
+ return some <| .git url rev? (← t.tryDecode? `subDir)
328
+ | .table ref t =>
329
+ return some <| .git (← t.tryDecode `url ref) rev? (← t.tryDecode? `subDir)
330
+ | _ =>
331
+ modify (·.push <| .mk g.ref "expected string or table")
332
+ return default
333
+ else
334
+ t.tryDecode? `source
335
+ let scope ← t.tryDecodeD `scope ""
336
+ let version? ← id do
337
+ if let some ver ← t.tryDecode? `version then
338
+ return some ver
339
+ else if let some rev := rev? then
340
+ return if src?.isSome then none else some s!"git#{rev}"
341
+ else
342
+ return none
343
+ let opts ← t.tryDecodeD `options {}
344
+ return {name, scope, version?, src?, opts}
345
+
346
+ instance : DecodeToml Dependency := ⟨fun v => do Dependency.decodeToml (← v.decodeTable) v.ref⟩
347
+
348
+ /-! ## Package & Target Configuration Decoders -/
349
+
350
+ private def genDecodeToml
351
+ (cmds : Array Command)
352
+ (tyName : Name) [info : ConfigInfo tyName] (takesName : Bool)
353
+ (exclude : Array Name := {})
354
+ : MacroM (Array Command) := do
355
+ let init ← `(TomlFieldInfos.empty)
356
+ let ty := if takesName then Syntax.mkCApp tyName #[mkIdent `n] else mkCIdent tyName
357
+ let infos ← info.fields.foldlM (init := init) fun infos {name, parent, ..} =>
358
+ if parent || exclude.contains name then
359
+ return infos
360
+ else
361
+ `($infos |>.insert $(quote name))
362
+ let instId ← mkIdentFromRef <| `_root_ ++ tyName.str "instConfigTomlInfo"
363
+ let cmds ← cmds.push <$> `(instance $instId:ident : ConfigTomlInfo $ty := ⟨$infos⟩)
364
+ let decId ← mkIdentFromRef <| `_root_ ++ tyName.str "decodeToml"
365
+ let cmds ← cmds.push <$> `(protected def $decId (t : Table) : DecodeM $ty := t.decodeConfig)
366
+ let instId ← mkIdentFromRef <| `_root_ ++ tyName.str "instDecodeToml"
367
+ let cmds ← cmds.push <$> `(instance $instId:ident : DecodeToml $ty := ⟨decodeTableValue $decId⟩)
368
+ return cmds
369
+
370
+ local macro "gen_toml_decoders%" : command => do
371
+ let cmds := #[]
372
+ -- Targets
373
+ let cmds ← genDecodeToml cmds ``LeanConfig false
374
+ let cmds ← genDecodeToml cmds ``LeanLibConfig true
375
+ (exclude := #[`nativeFacets])
376
+ let cmds ← genDecodeToml cmds ``LeanExeConfig true
377
+ (exclude := #[`nativeFacets])
378
+ let cmds ← genDecodeToml cmds ``InputFileConfig true
379
+ let cmds ← genDecodeToml cmds ``InputDirConfig true
380
+ -- Package
381
+ let cmds ← genDecodeToml cmds ``WorkspaceConfig false
382
+ let cmds ← genDecodeToml cmds ``PackageConfig true
383
+ return ⟨mkNullNode cmds⟩
384
+
385
+ gen_toml_decoders%
386
+
387
+ def decodeTargetDecls
388
+ (pkg : Name) (t : Table)
389
+ : DecodeM (Array (PConfigDecl pkg) × DNameMap (NConfigDecl pkg)) := do
390
+ let r := (#[], {})
391
+ let r ← go r LeanLib.keyword LeanLib.configKind LeanLibConfig.decodeToml
392
+ let r ← go r LeanExe.keyword LeanExe.configKind LeanExeConfig.decodeToml
393
+ let r ← go r InputFile.keyword InputFile.configKind InputFileConfig.decodeToml
394
+ let r ← go r InputDir.keyword InputDir.configKind InputDirConfig.decodeToml
395
+ return r
396
+ where
397
+ go r kw kind (decode : {n : Name} → Table → DecodeM (ConfigType kind pkg n)) := do
398
+ let some tableArrayVal := t.find? kw | return r
399
+ let some vals ← tryDecode? tableArrayVal.decodeValueArray | return r
400
+ vals.foldlM (init := r) fun r val => do
401
+ let some t ← tryDecode? val.decodeTable | return r
402
+ let some name ← tryDecode? <| stringToLegalOrSimpleName <$> t.decode `name
403
+ | return r
404
+ let (decls, map) := r
405
+ if let some orig := map.find? name then
406
+ modify fun es => es.push <| .mk val.ref s!"\
407
+ {pkg}: target '{name}' was already defined as a '{orig.kind}', \
408
+ but then redefined as a '{kind}'"
409
+ return (decls, map)
410
+ else
411
+ let config ← @decode name t
412
+ let decl : NConfigDecl pkg name :=
413
+ -- Safety: By definition, config kind = facet kind for declarative configurations.
414
+ unsafe {pkg, name, kind, config, wf_data := lcProof}
415
+ return (decls.push decl.toPConfigDecl, map.insert name decl)
416
+
417
+ /-! ## Root Loader -/
418
+
419
+ /-- Load a `Package` from a Lake configuration file written in TOML. -/
420
+ def loadTomlConfig (cfg: LoadConfig) : LogIO Package := do
421
+ let input ← IO.FS.readFile cfg.configFile
422
+ let ictx := mkInputContext input cfg.relConfigFile.toString
423
+ match (← loadToml ictx |>.toBaseIO) with
424
+ | .ok table =>
425
+ let .ok pkg errs := EStateM.run (s := #[]) do
426
+ let name ← stringToLegalOrSimpleName <$> table.tryDecode `name
427
+ let config ← @PackageConfig.decodeToml name table
428
+ let (targetDecls, targetDeclMap) ← decodeTargetDecls name table
429
+ let defaultTargets ← table.tryDecodeD `defaultTargets #[]
430
+ let defaultTargets := defaultTargets.map stringToLegalOrSimpleName
431
+ let depConfigs ← table.tryDecodeD `require #[]
432
+ return {
433
+ name := name
434
+ dir := cfg.pkgDir
435
+ relDir := cfg.relPkgDir
436
+ configFile := cfg.configFile
437
+ relConfigFile := cfg.relConfigFile
438
+ scope := cfg.scope
439
+ remoteUrl := cfg.remoteUrl
440
+ config, depConfigs, targetDecls, targetDeclMap
441
+ defaultTargets
442
+ }
443
+ if errs.isEmpty then
444
+ return pkg
445
+ else
446
+ errorWithLog <| errs.forM fun {ref, msg} =>
447
+ let pos := ictx.fileMap.toPosition <| ref.getPos?.getD 0
448
+ logError <| mkErrorStringWithPos ictx.fileName pos msg
449
+ | .error log =>
450
+ errorWithLog <| log.forM fun msg => do logError (← msg.toString)
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Load/Workspace.lean ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.Load.Resolve
8
+ import Lake.Build.InitFacets
9
+
10
+ /-! # Workspace Loader
11
+
12
+ This module contains the main definitions for loading a complete Lake workspace.
13
+ -/
14
+
15
+ open Lean
16
+
17
+ namespace Lake
18
+
19
+ /--
20
+ Load a `Workspace` for a Lake package by elaborating its configuration file.
21
+ Does not resolve dependencies.
22
+ -/
23
+ def loadWorkspaceRoot (config : LoadConfig) : LogIO Workspace := do
24
+ Lean.searchPathRef.set config.lakeEnv.leanSearchPath
25
+ let (root, env?) ← loadPackageCore "[root]" config
26
+ let root ← root.loadInputsFrom config.lakeEnv
27
+ let ws : Workspace := {
28
+ root
29
+ lakeEnv := config.lakeEnv
30
+ lakeArgs? := config.lakeArgs?
31
+ facetConfigs := initFacetConfigs
32
+ }
33
+ if let some env := env? then
34
+ IO.ofExcept <| ws.addFacetsFromEnv env config.leanOpts
35
+ else
36
+ return ws
37
+
38
+ /--
39
+ Load a `Workspace` for a Lake package by
40
+ elaborating its configuration file and resolving its dependencies.
41
+ If `updateDeps` is true, updates the manifest before resolving dependencies.
42
+ -/
43
+ def loadWorkspace (config : LoadConfig) : LoggerIO Workspace := do
44
+ let {reconfigure, leanOpts, updateDeps, updateToolchain, packageOverrides, ..} := config
45
+ let ws ← loadWorkspaceRoot config
46
+ if updateDeps then
47
+ ws.updateAndMaterialize {} leanOpts updateToolchain
48
+ else if let some manifest ← Manifest.load? ws.manifestFile then
49
+ ws.materializeDeps manifest leanOpts reconfigure packageOverrides
50
+ else
51
+ ws.updateAndMaterialize {} leanOpts updateToolchain
52
+
53
+ /-- Updates the manifest for the loaded Lake workspace (see `updateAndMaterialize`). -/
54
+ def updateManifest (config : LoadConfig) (toUpdate : NameSet := {})
55
+ : LoggerIO Unit := do
56
+ let {leanOpts, updateToolchain, ..} := config
57
+ let ws ← loadWorkspaceRoot config
58
+ discard <| ws.updateAndMaterialize toUpdate leanOpts updateToolchain
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Toml/Data.lean ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Lake.Toml.Data.Value
8
+
9
+ /-!
10
+ # TOML Data Types
11
+ -/
backend/core/leanprover--lean4---v4.22.0/src/lean/lake/Lake/Toml/Decode.lean ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Mac Malone. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Mac Malone
5
+ -/
6
+ prelude
7
+ import Init.System.FilePath
8
+ import Lake.Toml.Data
9
+
10
+ open Lean
11
+
12
+ /-!
13
+ # TOML Decoders
14
+
15
+ This module contains definitions to assist in decoding TOML data values
16
+ into concrete user types.
17
+ -/
18
+
19
+ namespace Lake
20
+
21
+ structure Toml.DecodeError where
22
+ ref : Syntax
23
+ msg : String
24
+
25
+ abbrev Toml.DecodeM := EStateM Empty (Array DecodeError)
26
+
27
+ abbrev Toml.EDecodeM := EStateM Unit (Array DecodeError)
28
+
29
+ class DecodeToml (α : Type) where
30
+ decode (v : Toml.Value) : Toml.EDecodeM α
31
+
32
+ abbrev decodeToml [DecodeToml α] (v : Toml.Value) : Toml.EDecodeM α :=
33
+ DecodeToml.decode v
34
+
35
+ namespace Toml
36
+
37
+ /-- Run the decode action. If there were errors, throw. Otherwise, return the result. -/
38
+ @[inline] def ensureDecode (x : DecodeM α) : EDecodeM α := fun es =>
39
+ match x es with
40
+ | .ok a es => if es.isEmpty then .ok a es else .error () es
41
+
42
+ /-- Run the decode action. If it fails, keep the errors but return `default`. -/
43
+ @[inline] def tryDecodeD (default : α) (x : EDecodeM α) : DecodeM α := fun es =>
44
+ match x es with
45
+ | .ok a es => .ok a es
46
+ | .error _ es => .ok default es
47
+
48
+ /-- Run the decode action. If it fails, keep the errors but return `none`. -/
49
+ @[inline] def tryDecode? (x : EDecodeM α) : DecodeM (Option α) := fun es =>
50
+ match x es with
51
+ | .ok a es => .ok (some a) es
52
+ | .error _ es => .ok none es
53
+
54
+ /-- Run the decode action. If it fails, keep the errors but return `Inhabited.default`. -/
55
+ @[inline] def tryDecode [Inhabited α] (x : EDecodeM α) : DecodeM α :=
56
+ tryDecodeD default x
57
+
58
+ /--
59
+ If the value is not `none`, run the decode action.
60
+ If it fails, add the errors to the state and return `default`.
61
+ -/
62
+ @[inline] def optDecodeD (default : β) (a? : Option α) (f : α → EDecodeM β) : DecodeM β :=
63
+ match a? with
64
+ | some a => tryDecodeD default (f a)
65
+ | none => pure default
66
+
67
+ /--
68
+ If the value is not `none`, run the decode action.
69
+ If it fails, add the errors to the state and return `Inhabited.default`.
70
+ -/
71
+ @[inline] def optDecode [Inhabited β] (a? : Option α) (f : α → EDecodeM β) : DecodeM β :=
72
+ optDecodeD default a? f
73
+
74
+ /--
75
+ If the value is not `none`, run the decode action.
76
+ If it fails, add the errors to the state and return `none`.
77
+ Otherwise, return the result in `some`.
78
+ -/
79
+ @[inline] def optDecode? (a? : Option α) (f : α → EDecodeM β) : DecodeM (Option β) :=
80
+ optDecodeD none a? fun a => some <$> f a
81
+
82
+ /--
83
+ If either action errors, throw the concatenated errors.
84
+ Otherwise, if no errors, combine the results with `f`.
85
+ -/
86
+ def mergeErrors (x₁ : EDecodeM α) (x₂ : EDecodeM β) (f : α → β → γ) : EDecodeM γ := fun es =>
87
+ match x₁ es with
88
+ | .ok a es =>
89
+ match x₂ es with
90
+ | .ok b es => .ok (f a b) es
91
+ | .error _ es => .error () es
92
+ | .error _ es => .error () es
93
+
94
+ @[inline] def throwDecodeErrorAt (ref : Syntax) (msg : String) : EDecodeM α :=
95
+ fun es => .error () (es.push {ref, msg})
96
+
97
+ /-- Decode an array of TOML values, merging any errors from the elements into a single array. -/
98
+ def decodeArray [dec : DecodeToml α] (vs : Array Value) : EDecodeM (Array α) :=
99
+ vs.foldl (init := pure (.mkEmpty vs.size)) fun vs v =>
100
+ mergeErrors vs (dec.decode v) Array.push
101
+
102
+ instance : DecodeToml Value := ⟨pure⟩
103
+
104
+ namespace Value
105
+
106
+ def decodeString : Value → EDecodeM String
107
+ | .string _ v => .ok v
108
+ | x => throwDecodeErrorAt x.ref "expected string"
109
+
110
+ instance : DecodeToml String := ⟨decodeString⟩
111
+ instance : DecodeToml System.FilePath := ⟨(.mk <$> decodeToml ·)⟩
112
+
113
+ def decodeName (v : Value) : EDecodeM Name := do
114
+ match (← v.decodeString).toName with
115
+ | .anonymous => throwDecodeErrorAt v.ref "expected name"
116
+ | n => pure n
117
+
118
+ instance : DecodeToml Lean.Name := ⟨decodeName⟩
119
+
120
+ def decodeInt : Value → EDecodeM Int
121
+ | .integer _ v => .ok v
122
+ | x => throwDecodeErrorAt x.ref "expected integer"
123
+
124
+ instance : DecodeToml Int := ⟨decodeInt⟩
125
+
126
+ def decodeNat : Value → EDecodeM Nat
127
+ | .integer _ (.ofNat v) => .ok v
128
+ | x => throwDecodeErrorAt x.ref "expected nonnegative integer"
129
+
130
+ instance : DecodeToml Nat := ⟨decodeNat⟩
131
+
132
+ def decodeFloat : Value → EDecodeM Float
133
+ | .float _ v => .ok v
134
+ | x => throwDecodeErrorAt x.ref "expected float"
135
+
136
+ instance : DecodeToml Float := ⟨decodeFloat⟩
137
+
138
+ def decodeBool : Value → EDecodeM Bool
139
+ | .boolean _ v => .ok v
140
+ | x => throwDecodeErrorAt x.ref "expected boolean"
141
+
142
+ instance : DecodeToml Bool := ⟨decodeBool⟩
143
+
144
+ def decodeDateTime : Value → EDecodeM DateTime
145
+ | .dateTime _ v => .ok v
146
+ | x => throwDecodeErrorAt x.ref "expected date-time"
147
+
148
+ instance : DecodeToml DateTime := ⟨decodeDateTime⟩
149
+
150
+ def decodeValueArray : Value → EDecodeM (Array Value)
151
+ | .array _ vs => .ok vs
152
+ | x => throwDecodeErrorAt x.ref "expected array"
153
+
154
+ @[inline] protected def decodeArray [dec : DecodeToml α] (v : Value) : EDecodeM (Array α) := do
155
+ decodeArray (dec := dec) (← v.decodeValueArray)
156
+
157
+ instance [DecodeToml α] : DecodeToml (Array α) := ⟨Value.decodeArray⟩
158
+
159
+ @[inline] def decodeArrayOrSingleton [dec : DecodeToml α] : Value → EDecodeM (Array α)
160
+ | .array _ vs => decodeArray (dec := dec) vs
161
+ | v => Array.singleton <$> dec.decode v
162
+
163
+ def decodeTable : Value → EDecodeM Table
164
+ | .table _ t => .ok t
165
+ | x => throwDecodeErrorAt x.ref "expected table"
166
+
167
+ instance : DecodeToml Table := ⟨(·.decodeTable)⟩
168
+
169
+ end Value
170
+
171
+ def decodeKeyval [dec : DecodeToml α] (k : Name) (v : Value) : EDecodeM α := fun es =>
172
+ let iniPos := es.size
173
+ let f es := es.mapIdx fun i e =>
174
+ if iniPos ≤ i then {e with msg := s!"key {ppKey k}: {e.msg}"} else e
175
+ match dec.decode v es with
176
+ | .ok a es => .ok a (f es)
177
+ | .error e es => .error e (f es)
178
+
179
+ namespace Table
180
+
181
+ def decodeValue (t : Table) (k : Name) (ref := Syntax.missing) : EDecodeM Value := do
182
+ let some a := t.find? k
183
+ | throwDecodeErrorAt ref s!"missing required key: {ppKey k}"
184
+ return a
185
+
186
+ @[inline] def decode [dec : DecodeToml α] (t : Table) (k : Name) (ref := Syntax.missing) : EDecodeM α := do
187
+ let a ← t.decodeValue k ref
188
+ decodeKeyval (dec := dec) k a
189
+
190
+ @[inline] def decode? [dec : DecodeToml α] (t : Table) (k : Name) : EDecodeM (Option α) := do
191
+ t.find? k |>.mapM fun v => decodeKeyval (dec := dec) k v
192
+
193
+ def decodeNameMap [dec : DecodeToml α] (t : Toml.Table) : EDecodeM (NameMap α) := do
194
+ t.items.foldl (init := pure {}) fun m (k,v) =>
195
+ mergeErrors m (dec.decode v) fun m v => m.insert k v
196
+
197
+ instance [DecodeToml α] : DecodeToml (NameMap α) := ⟨(do decodeNameMap <| ← ·.decodeTable)⟩
198
+
199
+ @[inline] protected def tryDecode [Inhabited α] [dec : DecodeToml α] (t : Table) (k : Name) (ref := Syntax.missing) : DecodeM α := do
200
+ tryDecode <| t.decode (dec := dec) k ref
201
+
202
+ @[inline] protected def tryDecode? [dec : DecodeToml α] (t : Table) (k : Name) : DecodeM (Option α) :=
203
+ optDecode? (t.find? k) dec.decode
204
+
205
+ @[inline] protected def tryDecodeD [dec : DecodeToml α] (k : Name) (default : α) (t : Table) : DecodeM α :=
206
+ optDecodeD default (t.find? k) dec.decode
207
+
208
+ end Table