lean4-htt/src/Lean/Util/Path.lean
2020-09-25 11:22:06 +02:00

87 lines
3.3 KiB
Text

/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Sebastian Ullrich
Management of the Lean search path (`LEAN_PATH`), which is a list of
paths containing package roots: an import `A.B.C` resolves to
`path/A/B/C.olean` for the first entry `path` in `LEAN_PATH`
with a directory `A/`. `import A` resolves to `path/A.olean`.
-/
import Lean.Data.Name
namespace Lean
open System.FilePath (pathSeparator extSeparator)
private def pathSep : String := toString pathSeparator
def realPathNormalized (fname : String) : IO String := do
fname ← IO.realPath fname;
pure (System.FilePath.normalizePath fname)
abbrev SearchPath := List String
def mkSearchPathRef : IO (IO.Ref SearchPath) :=
IO.mkRef ∅
@[init mkSearchPathRef]
constant searchPathRef : IO.Ref SearchPath := arbitrary _
def parseSearchPath (path : String) (sp : SearchPath := ∅) : IO SearchPath :=
pure $ System.FilePath.splitSearchPath path ++ sp
@[extern c inline "LEAN_IS_STAGE0"]
constant isStage0 (u : Unit) : Bool := arbitrary _
def getBuiltinSearchPath : IO SearchPath := do
appDir ← IO.appDir;
-- use stage1 stdlib with stage0 executable (which should never be distributed outside of the build directory)
pure [appDir ++ pathSep ++ ".." ++ (if isStage0 () then pathSep ++ ".." ++ pathSep ++ "stage1" else "") ++ pathSep ++ "lib" ++ pathSep ++ "lean"]
def addSearchPathFromEnv (sp : SearchPath) : IO SearchPath := do
val ← IO.getEnv "LEAN_PATH";
match val with
| none => pure sp
| some val => parseSearchPath val sp
@[export lean_init_search_path]
def initSearchPath (path : Option String := none) : IO Unit :=
match path with
| some path => parseSearchPath path >>= searchPathRef.set
| none => do
sp ← getBuiltinSearchPath;
sp ← addSearchPathFromEnv sp;
searchPathRef.set sp
def modPathToFilePath : Name → String
| Name.str p h _ => modPathToFilePath p ++ pathSep ++ h
| Name.anonymous => ""
| Name.num p _ _ => panic! "ill-formed import"
def findOLean (mod : Name) : IO String := do
sp ← searchPathRef.get;
let pkg := mod.getRoot.toString;
some root ← sp.findM? (fun path => IO.isDir $ path ++ pathSep ++ pkg)
| throw $ IO.userError $ "unknown package '" ++ pkg ++ "'";
pure $ root ++ modPathToFilePath mod ++ ".olean"
/-- Infer module name of source file name. -/
@[export lean_module_name_of_file]
def moduleNameOfFileName (fname : String) (rootDir : Option String) : IO Name := do
fname ← realPathNormalized fname;
rootDir ← match rootDir with
| some rootDir => pure rootDir
| none => IO.currentDir;
rootDir ← realPathNormalized rootDir;
when (!rootDir.isPrefixOf fname) $
throw $ IO.userError $ "input file '" ++ fname ++ "' must be contained in root directory (" ++ rootDir ++ ")";
let fnameSuffix := fname.drop rootDir.length;
let fnameSuffix := if fnameSuffix.get 0 == pathSeparator then fnameSuffix.drop 1 else fnameSuffix;
some extPos ← pure (fnameSuffix.revPosOf '.')
| throw (IO.userError ("failed to convert file name '" ++ fname ++ "' to module name, extension is missing"));
let modNameStr := fnameSuffix.extract 0 extPos;
let extStr := fnameSuffix.extract (extPos + 1) fnameSuffix.bsize;
let parts := modNameStr.splitOn pathSep;
let modName := parts.foldl mkNameStr Name.anonymous;
pure modName
end Lean