Skip to content

Commit 1fb3974

Browse files
committed
Very WIP library dependency resolution
1 parent f141206 commit 1fb3974

File tree

20 files changed

+481
-236
lines changed

20 files changed

+481
-236
lines changed

agda-language-server.cabal

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ library
6363
Indexer.Indexer
6464
Indexer.Monad
6565
Indexer.Postprocess
66+
Indexer.Prepare
6667
Language.LSP.Protocol.Types.More
6768
Language.LSP.Protocol.Types.Uri.More
6869
Monad
@@ -92,6 +93,7 @@ library
9293
Server.Model.AgdaLib
9394
Server.Model.AgdaProject
9495
Server.Model.Handler
96+
Server.Model.InstalledLibsFile
9597
Server.Model.Monad
9698
Server.Model.Symbol
9799
Server.ResponseController
@@ -106,7 +108,7 @@ library
106108
OverloadedStrings
107109
PatternSynonyms
108110
TypeOperators
109-
ghc-options: -Wincomplete-patterns -Werror=incomplete-patterns -Wunused-local-binds -Wunused-pattern-binds -Wunused-do-bind -Wunused-foralls -Wunused-imports -Wwarnings-deprecations -Wwrong-do-bind -Wmissing-fields -Wmissing-methods -Wmissing-pattern-synonym-signatures -Wmissing-signatures -Wsimplifiable-class-constraints -fno-warn-orphans -Werror
111+
ghc-options: -Wincomplete-patterns -Werror=incomplete-patterns -Wunused-local-binds -Wunused-pattern-binds -Wunused-do-bind -Wunused-foralls -Wunused-imports -Wwarnings-deprecations -Wwrong-do-bind -Wmissing-fields -Wmissing-methods -Wmissing-pattern-synonym-signatures -Wmissing-signatures -Wsimplifiable-class-constraints -fno-warn-orphans
110112
build-depends:
111113
Agda
112114
, aeson
@@ -153,7 +155,7 @@ executable als
153155
OverloadedStrings
154156
PatternSynonyms
155157
TypeOperators
156-
ghc-options: -Wincomplete-patterns -Werror=incomplete-patterns -Wunused-local-binds -Wunused-pattern-binds -Wunused-do-bind -Wunused-foralls -Wunused-imports -Wwarnings-deprecations -Wwrong-do-bind -Wmissing-fields -Wmissing-methods -Wmissing-pattern-synonym-signatures -Wmissing-signatures -Wsimplifiable-class-constraints -fno-warn-orphans -Werror -rtsopts
158+
ghc-options: -Wincomplete-patterns -Werror=incomplete-patterns -Wunused-local-binds -Wunused-pattern-binds -Wunused-do-bind -Wunused-foralls -Wunused-imports -Wwarnings-deprecations -Wwrong-do-bind -Wmissing-fields -Wmissing-methods -Wmissing-pattern-synonym-signatures -Wmissing-signatures -Wsimplifiable-class-constraints -fno-warn-orphans -rtsopts
157159
build-depends:
158160
Agda
159161
, aeson
@@ -225,6 +227,7 @@ test-suite als-test
225227
Indexer.Indexer
226228
Indexer.Monad
227229
Indexer.Postprocess
230+
Indexer.Prepare
228231
Language.LSP.Protocol.Types.More
229232
Language.LSP.Protocol.Types.Uri.More
230233
Monad
@@ -254,6 +257,7 @@ test-suite als-test
254257
Server.Model.AgdaLib
255258
Server.Model.AgdaProject
256259
Server.Model.Handler
260+
Server.Model.InstalledLibsFile
257261
Server.Model.Monad
258262
Server.Model.Symbol
259263
Server.ResponseController
@@ -268,7 +272,7 @@ test-suite als-test
268272
OverloadedStrings
269273
PatternSynonyms
270274
TypeOperators
271-
ghc-options: -Wincomplete-patterns -Werror=incomplete-patterns -Wunused-local-binds -Wunused-pattern-binds -Wunused-do-bind -Wunused-foralls -Wunused-imports -Wwarnings-deprecations -Wwrong-do-bind -Wmissing-fields -Wmissing-methods -Wmissing-pattern-synonym-signatures -Wmissing-signatures -Wsimplifiable-class-constraints -fno-warn-orphans -Werror -rtsopts
275+
ghc-options: -Wincomplete-patterns -Werror=incomplete-patterns -Wunused-local-binds -Wunused-pattern-binds -Wunused-do-bind -Wunused-foralls -Wunused-imports -Wwarnings-deprecations -Wwrong-do-bind -Wmissing-fields -Wmissing-methods -Wmissing-pattern-synonym-signatures -Wmissing-signatures -Wsimplifiable-class-constraints -fno-warn-orphans -rtsopts
272276
build-depends:
273277
Agda
274278
, aeson

src/Agda/Interaction/Imports/Virtual.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ parseSourceFromContents srcUri srcFile contentsStrict = do
8181
parsedModName <- TCM.liftTCM $ Imp.moduleName f parsedMod
8282

8383
agdaLib <- askAgdaLib
84-
let libs = maybeToList $ agdaLibToFile srcUri agdaLib
84+
let libs = maybeToList $ agdaLibToFile srcUri <$> agdaLib
8585

8686
return
8787
Imp.Source

src/Agda/Interaction/Library/More.hs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{-# LANGUAGE CPP #-}
22

33
module Agda.Interaction.Library.More
4-
( tryRunLibM,
4+
( defaultLibraryFileIds,
5+
tryRunLibM,
56
#if MIN_VERSION_Agda(2,8,0)
67
#else
78
runLibErrorIO,
@@ -29,6 +30,24 @@ import Control.Monad.State.Lazy (evalStateT)
2930
import Control.Monad.Writer.Lazy (runWriterT)
3031
import Agda.Syntax.Common.Pretty (Pretty, pretty, text, (<+>))
3132
import Agda.Utils.Lens ((^.))
33+
import Agda.Utils.List1 (List1, NonEmpty ((:|)))
34+
import Agda.Version (version)
35+
import qualified Server.Filesystem as FS
36+
37+
-- | The @~/.agda/libraries@ file lists the libraries Agda should know about.
38+
-- The content of @libraries@ is a list of paths to @.agda-lib@ files.
39+
--
40+
-- Agda honors also version-specific @libraries@ files, e.g. @libraries-2.6.0@.
41+
--
42+
-- @defaultLibraryFiles@ gives a list of all @libraries@ files Agda should process
43+
-- by default. The first file in this list that exists is actually used.
44+
--
45+
defaultLibraryFiles :: List1 FilePath
46+
defaultLibraryFiles = ("libraries-" ++ version) :| "libraries" : []
47+
48+
defaultLibraryFileIds :: (MonadIO m) => FS.FileId -> m (List1 FS.FileId)
49+
defaultLibraryFileIds agdaDir =
50+
traverse (`FS.fileIdRelativeTo` agdaDir) . fmap FS.LocalFilePath $ defaultLibraryFiles
3251

3352
#if MIN_VERSION_Agda(2,8,0)
3453
-- Unneeded in 2.8.0 due to API changes

src/Agda/Interaction/Library/Parse/More.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
module Agda.Interaction.Library.Parse.More
1111
( parseLibFile,
1212
runP,
13+
trimLineComment,
1314
)
1415
where
1516

@@ -277,6 +278,10 @@ groupLines (Header _ h : ls) = (GenericEntry h [c | Content _ c <- cs] :) <$> gr
277278
splitCommas :: String -> [String]
278279
splitCommas = words . map (\c -> if c == ',' then ' ' else c)
279280

281+
-- | Remove leading whitespace and line comment.
282+
trimLineComment :: String -> String
283+
trimLineComment = stripComments . ltrim
284+
280285
-- | ...and trailing, but not leading, whitespace.
281286
stripComments :: String -> String
282287
stripComments "" = ""
Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module Agda.TypeChecking.Monad.Options.More (setCommandLineOptionsByLib) where
1+
module Agda.TypeChecking.Monad.Options.More () where
22

33
import Agda.Interaction.Options (CommandLineOptions (..))
44
import qualified Agda.Interaction.Options.Lenses as Lens
@@ -15,45 +15,45 @@ import Server.Model.AgdaLib (AgdaLib, agdaLibDependencies, agdaLibIncludes)
1515
import Server.Model.Monad (MonadAgdaProject, askAgdaLib)
1616
import System.Directory (getCurrentDirectory)
1717

18-
setCommandLineOptionsByLib ::
19-
(MonadTCM m, MonadAgdaProject m) =>
20-
CommandLineOptions ->
21-
m ()
22-
setCommandLineOptionsByLib opts = do
23-
root <- liftIO (absolute =<< getCurrentDirectory)
24-
setCommandLineOptionsByLib' root opts
18+
-- setCommandLineOptionsByLib ::
19+
-- (MonadTCM m, MonadAgdaProject m) =>
20+
-- CommandLineOptions ->
21+
-- m ()
22+
-- setCommandLineOptionsByLib opts = do
23+
-- root <- liftIO (absolute =<< getCurrentDirectory)
24+
-- setCommandLineOptionsByLib' root opts
2525

26-
setCommandLineOptionsByLib' ::
27-
(MonadTCM m, MonadAgdaProject m) =>
28-
AbsolutePath ->
29-
CommandLineOptions ->
30-
m ()
31-
setCommandLineOptionsByLib' root opts = do
32-
incs <- case optAbsoluteIncludePaths opts of
33-
[] -> do
34-
opts' <- setLibraryPathsByLib opts
35-
let incs = optIncludePaths opts'
36-
TCM.liftTCM $ TCM.setIncludeDirs incs root
37-
List1.toList <$> TCM.getIncludeDirs
38-
incs -> return incs
39-
TCM.modifyTC $ Lens.setCommandLineOptions opts {optAbsoluteIncludePaths = incs}
40-
TCM.liftTCM $ TCM.setPragmaOptions (optPragmaOptions opts)
41-
TCM.liftTCM updateBenchmarkingStatus
26+
-- setCommandLineOptionsByLib' ::
27+
-- (MonadTCM m, MonadAgdaProject m) =>
28+
-- AbsolutePath ->
29+
-- CommandLineOptions ->
30+
-- m ()
31+
-- setCommandLineOptionsByLib' root opts = do
32+
-- incs <- case optAbsoluteIncludePaths opts of
33+
-- [] -> do
34+
-- opts' <- setLibraryPathsByLib opts
35+
-- let incs = optIncludePaths opts'
36+
-- TCM.liftTCM $ TCM.setIncludeDirs incs root
37+
-- List1.toList <$> TCM.getIncludeDirs
38+
-- incs -> return incs
39+
-- TCM.modifyTC $ Lens.setCommandLineOptions opts {optAbsoluteIncludePaths = incs}
40+
-- TCM.liftTCM $ TCM.setPragmaOptions (optPragmaOptions opts)
41+
-- TCM.liftTCM updateBenchmarkingStatus
4242

43-
setLibraryPathsByLib ::
44-
(MonadTCM m, MonadAgdaProject m) =>
45-
CommandLineOptions ->
46-
m CommandLineOptions
47-
setLibraryPathsByLib o = do
48-
agdaLib <- askAgdaLib
49-
return $ addDefaultLibrariesByLib agdaLib o
43+
-- setLibraryPathsByLib ::
44+
-- (MonadTCM m, MonadAgdaProject m) =>
45+
-- CommandLineOptions ->
46+
-- m CommandLineOptions
47+
-- setLibraryPathsByLib o = do
48+
-- agdaLib <- askAgdaLib
49+
-- return $ addDefaultLibrariesByLib agdaLib o
5050

51-
-- TODO: resolve dependency libs; see setLibraryIncludes in Agda
51+
-- -- TODO: resolve dependency libs; see setLibraryIncludes in Agda
5252

53-
addDefaultLibrariesByLib :: AgdaLib -> CommandLineOptions -> CommandLineOptions
54-
addDefaultLibrariesByLib agdaLib o
55-
| not (null $ optLibraries o) || not (optUseLibs o) = o
56-
| otherwise = do
57-
let libs = agdaLib ^. agdaLibDependencies
58-
let incs = uriToPossiblyInvalidFilePath . FS.fileIdToUri <$> agdaLib ^. agdaLibIncludes
59-
o {optIncludePaths = incs ++ optIncludePaths o, optLibraries = libs}
53+
-- addDefaultLibrariesByLib :: AgdaLib -> CommandLineOptions -> CommandLineOptions
54+
-- addDefaultLibrariesByLib agdaLib o
55+
-- | not (null $ optLibraries o) || not (optUseLibs o) = o
56+
-- | otherwise = do
57+
-- let libs = agdaLib ^. agdaLibDependencies
58+
-- let incs = uriToPossiblyInvalidFilePath . FS.fileIdToUri <$> agdaLib ^. agdaLibIncludes
59+
-- o {optIncludePaths = incs ++ optIncludePaths o, optLibraries = libs}

src/Indexer.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,23 @@ import qualified Agda.Interaction.Imports.More as Imp
1616
import qualified Agda.Syntax.Concrete as C
1717
import Agda.Syntax.Translation.ConcreteToAbstract (ToAbstract (toAbstract), TopLevel (TopLevel), TopLevelInfo)
1818
import qualified Agda.TypeChecking.Monad as TCM
19-
import Agda.TypeChecking.Monad.Options.More (setCommandLineOptionsByLib)
2019
import qualified Data.Map as Map
2120
import Indexer.Indexer (indexAst)
2221
import Indexer.Monad (execIndexerM)
2322
import Indexer.Postprocess (postprocess)
2423
import Server.Model.AgdaFile (AgdaFile)
2524
import Server.Model.Monad (WithAgdaProjectM)
25+
import Indexer.Prepare (setCommandLineOptionsByLib)
2626

2727
usingSrcAsCurrent :: Imp.Source -> WithAgdaProjectM a -> WithAgdaProjectM a
2828
usingSrcAsCurrent src x = do
2929
TCM.liftTCM TCM.resetState
3030

3131
TCM.liftTCM $ Imp.setOptionsFromSourcePragmas True src
3232

33-
TCM.setCurrentRange (C.modPragmas . Imp.srcModule $ src) $
34-
-- Now reset the options
35-
setCommandLineOptionsByLib . TCM.stPersistentOptions . TCM.stPersistentState =<< TCM.getTC
33+
TCM.setCurrentRange (C.modPragmas . Imp.srcModule $ src) $ do
34+
persistentOptions <- TCM.stPersistentOptions . TCM.stPersistentState <$> TCM.getTC
35+
setCommandLineOptionsByLib persistentOptions
3636

3737
#if MIN_VERSION_Agda(2,8,0)
3838
TCM.modifyTCLens TCM.stModuleToSourceId $ Map.insert (Imp.srcModuleName src) (Imp.srcOrigin src)

src/Indexer/Prepare.hs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
module Indexer.Prepare (setCommandLineOptionsByLib) where
2+
3+
import Agda.Interaction.Library (LibName)
4+
import Agda.Interaction.Library.Base (libNameForCurrentDir)
5+
import Agda.Interaction.Options (CommandLineOptions (..))
6+
import qualified Agda.Interaction.Options.Lenses as Lens
7+
import qualified Agda.TypeChecking.Monad as TCM
8+
import Agda.TypeChecking.Monad.Benchmark (updateBenchmarkingStatus)
9+
import Agda.Utils.FileName (AbsolutePath, absolute)
10+
import Agda.Utils.Impossible (__IMPOSSIBLE__)
11+
import Agda.Utils.Lens ((^.))
12+
import qualified Agda.Utils.List1 as List1
13+
import Agda.Utils.Maybe (ifJustM, maybeToList)
14+
import Agda.Utils.Monad (lift)
15+
import Control.Monad.IO.Class (liftIO)
16+
import qualified Server.AgdaLibResolver as AgdaLibResolver
17+
import qualified Server.Filesystem as FS
18+
import Server.Model.AgdaLib (AgdaLib, agdaLibDependencies, agdaLibIncludes, agdaLibName)
19+
import Server.Model.Monad (MonadAgdaProject, WithAgdaProjectM, askAgdaLib)
20+
import System.Directory (getCurrentDirectory)
21+
22+
setCommandLineOptionsByLib :: CommandLineOptions -> WithAgdaProjectM ()
23+
setCommandLineOptionsByLib opts = do
24+
root <- liftIO (absolute =<< getCurrentDirectory)
25+
setCommandLineOptionsByLib' root opts
26+
27+
setCommandLineOptionsByLib' :: AbsolutePath -> CommandLineOptions -> WithAgdaProjectM ()
28+
setCommandLineOptionsByLib' root opts = do
29+
incs <- case optAbsoluteIncludePaths opts of
30+
[] -> do
31+
opts' <- updateOptionsWithDependencyLibs opts
32+
let incs = optIncludePaths opts'
33+
TCM.liftTCM $ TCM.setIncludeDirs incs root
34+
List1.toList <$> TCM.getIncludeDirs
35+
incs -> return incs
36+
TCM.modifyTC $ Lens.setCommandLineOptions opts {optAbsoluteIncludePaths = incs}
37+
TCM.liftTCM $ TCM.setPragmaOptions (optPragmaOptions opts)
38+
TCM.liftTCM updateBenchmarkingStatus
39+
40+
-- | Determine the libraries we directly depend on
41+
directDependencyLibNames ::
42+
(MonadAgdaProject m) =>
43+
-- | Persistent command line options
44+
CommandLineOptions ->
45+
m [LibName]
46+
directDependencyLibNames persistentOptions
47+
| not (null $ optLibraries persistentOptions) = return $ optLibraries persistentOptions
48+
| not (optUseLibs persistentOptions) = return []
49+
| otherwise =
50+
ifJustM
51+
askAgdaLib
52+
(\agdaLib -> return $ agdaLib ^. agdaLibDependencies)
53+
(defaultLibNames persistentOptions)
54+
55+
-- | Determine the libraries we depend on when there is no .agda-lib
56+
-- TODO: read from default file
57+
defaultLibNames ::
58+
(MonadAgdaProject m) =>
59+
CommandLineOptions ->
60+
m [LibName]
61+
defaultLibNames persistentOptions
62+
| optDefaultLibs persistentOptions = return [libNameForCurrentDir]
63+
| otherwise = return []
64+
65+
dependencyLibs :: CommandLineOptions -> WithAgdaProjectM [AgdaLib]
66+
dependencyLibs persistentOptions = do
67+
directDependencies <- directDependencyLibNames persistentOptions
68+
installed <- lift $ AgdaLibResolver.installedLibraries (FS.LocalFilePath <$> optOverrideLibrariesFile persistentOptions)
69+
let libs = resolveDeps installed directDependencies [] []
70+
case libs of
71+
Nothing -> __IMPOSSIBLE__ -- TODO: very wrong, do real error handling
72+
Just libs -> do
73+
projectLib <- askAgdaLib
74+
return $ maybeToList projectLib <> libs
75+
where
76+
resolveDeps :: [AgdaLib] -> [LibName] -> [LibName] -> [AgdaLib] -> Maybe [AgdaLib]
77+
resolveDeps _installed [] _doneNames doneLibs = Just doneLibs
78+
resolveDeps installed (next : todo) doneNames doneLibs
79+
| next `elem` doneNames = resolveDeps installed todo doneNames doneLibs
80+
| otherwise = do
81+
lib <- AgdaLibResolver.byLibName next installed
82+
let newDeps = lib ^. agdaLibDependencies
83+
resolveDeps installed (newDeps <> todo) (next : doneNames) (lib : doneLibs)
84+
85+
updateOptionsWithDependencyLibs :: CommandLineOptions -> WithAgdaProjectM CommandLineOptions
86+
updateOptionsWithDependencyLibs o = do
87+
libs <- dependencyLibs o
88+
let includes = concatMap (^. agdaLibIncludes) libs
89+
let libNames = fmap (^. agdaLibName) libs
90+
let includePaths = FS.fileIdToPossiblyInvalidFilePath <$> includes
91+
return $
92+
o
93+
{ optIncludePaths = includePaths <> optIncludePaths o,
94+
optLibraries = libNames
95+
}

src/Monad.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ createInitEnv options =
6565
<*> liftIO ResponseController.new
6666
<*> (pure $ FS.Layered [FS.Wrap FS.LspVirtualFilesystem, FS.Wrap FS.OsFilesystem])
6767
<*> liftIO (newIORef VfsIndex.empty)
68-
<*> liftIO (newIORef Model.empty)
68+
<*> liftIO (newIORef Model.mkEmpty)
6969

7070
--------------------------------------------------------------------------------
7171

0 commit comments

Comments
 (0)