Skip to content

Commit e0dfe3d

Browse files
committed
actually topo sort defs
1 parent 5cf5a5b commit e0dfe3d

File tree

4 files changed

+89
-13
lines changed

4 files changed

+89
-13
lines changed

src/Agda2Lambox/Compile.hs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@ module Agda2Lambox.Compile
66
import Control.Monad.IO.Class ( liftIO )
77
import Data.IORef
88

9+
import Control.Monad.State
10+
11+
import Data.Bifunctor (bimap)
12+
import Data.Set (Set)
13+
import Data.Map (Map)
14+
import Data.Map qualified as Map
15+
import Data.Set qualified as Set
916
import Agda.Compiler.Backend
1017
import Agda.Syntax.Internal ( QName )
1118
import Agda.Syntax.Common (Arg(..))
1219
import Agda.Syntax.Common.Pretty ( prettyShow )
1320
import Agda.TypeChecking.Monad ( liftTCM, getConstInfo )
1421
import Agda.TypeChecking.Pretty
15-
import Agda.Utils.Monad ( whenM, ifM, unlessM, ifNotM, orM )
22+
import Agda.Utils.Monad ( whenM, ifM, unlessM, ifNotM, orM, forM_ )
1623

1724
import Agda.Utils ( hasPragma, isDataOrRecDef, treeless, isArity )
1825

@@ -29,12 +36,46 @@ import LambdaBox.Env (GlobalEnv(..), GlobalDecl(..), ConstantBody(..))
2936
import LambdaBox.Type qualified as LamBox
3037

3138
import Agda2Lambox.Compile.Type (compileTopLevelType)
39+
import Data.Foldable (foldrM)
40+
import Agda.Utils.Maybe (catMaybes, mapMaybe, isJust)
3241

3342
-- | Compile the given names to a λ□ environment.
3443
compile :: Target t -> [QName] -> TCM (GlobalEnv t)
35-
compile t qs = GlobalEnv <$> compileLoop (compileDefinition t) qs
44+
compile t qs = do
45+
items <- topoSort <$> compileLoop (compileDefinition t) qs
46+
47+
let skipped = flip mapMaybe items \item ->
48+
case itemValue item of
49+
Nothing -> Nothing
50+
Just x -> Just (item { itemValue = x })
51+
52+
pure $ GlobalEnv $ flip map skipped \CompiledItem{..} ->
53+
(qnameToKName itemName, itemValue)
54+
55+
56+
-- TODO(flupe): move this somewhere else
57+
type TopoM a = State (Set QName, [CompiledItem a])
58+
59+
topoSort :: forall a. [CompiledItem a] -> [CompiledItem a]
60+
topoSort defs = snd $ execState (traverse (visit Set.empty) defs) (Set.empty, [])
61+
where
62+
items = Map.fromList $ map (\x -> (itemName x, x)) defs
63+
64+
isMarked :: QName -> TopoM a Bool
65+
isMarked q = Set.member q <$> gets fst
66+
67+
push :: CompiledItem a -> TopoM a ()
68+
push item@CompiledItem{itemName} = modify $ bimap (Set.insert itemName) (item:)
69+
70+
visit :: Set QName -> CompiledItem a -> TopoM a ()
71+
visit temp item@CompiledItem{..} = do
72+
unlessM ((Set.member itemName temp ||) <$> isMarked itemName) do
73+
let deps = catMaybes $ (`Map.lookup` items) <$> itemDeps
74+
traverse (visit (Set.insert itemName temp)) deps
75+
push item
76+
3677

37-
compileDefinition :: Target t -> Definition -> CompileM (Maybe (KerName, GlobalDecl t))
78+
compileDefinition :: Target t -> Definition -> CompileM (Maybe (GlobalDecl t))
3879
compileDefinition target defn@Defn{..} = setCurrentRange defName do
3980
reportSDoc "agda2lambox.compile" 1 $ "Compiling definition: " <+> prettyTCM defName
4081

@@ -45,8 +86,8 @@ compileDefinition target defn@Defn{..} = setCurrentRange defName do
4586
, liftTCM $ isLogical $ Arg defArgInfo defType])
4687
(pure Nothing) do
4788

48-
-- prepend kername
49-
fmap (qnameToKName defName,) <$> case theDef of
89+
case theDef of
90+
PrimitiveSort{} -> pure Nothing
5091
GeneralizableVar{} -> pure Nothing
5192

5293
Axiom{} -> do

src/Agda2Lambox/Compile/Monad.hs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# LANGUAGE DerivingVia, GeneralizedNewtypeDeriving, OverloadedStrings #-}
1+
{-# LANGUAGE DerivingVia, GeneralizedNewtypeDeriving, OverloadedStrings, DeriveFunctor, DeriveTraversable #-}
22
-- | Compilation monad.
33
module Agda2Lambox.Compile.Monad
44
( CompileM
@@ -7,6 +7,7 @@ module Agda2Lambox.Compile.Monad
77
, genericError
88
, genericDocError
99
, internalError
10+
, CompiledItem(..)
1011
) where
1112

1213
import Control.Monad ( unless )
@@ -18,7 +19,7 @@ import Queue.Ephemeral ( EphemeralQueue(..) )
1819
import Queue.Ephemeral qualified as Queue
1920

2021
import Agda.Syntax.Abstract (QName)
21-
import Agda.Compiler.Backend (getConstInfo, PureTCM, HasConstInfo, HasBuiltins)
22+
import Agda.Compiler.Backend (getConstInfo, PureTCM, HasConstInfo, HasBuiltins, canonicalName)
2223
import Agda.TypeChecking.Monad (MonadDebug, MonadTrace, MonadAddContext)
2324
import Agda.TypeChecking.Monad.Debug (MonadDebug, reportSDoc)
2425
import Agda.TypeChecking.Monad.Base hiding (initState)
@@ -32,6 +33,8 @@ data CompileState = CompileState
3233
-- ^ Names that we have seen, either already compiled or in the queue.
3334
, compileQueue :: EphemeralQueue QName
3435
-- ^ Compilation queue.
36+
, requiredDefs :: Set QName
37+
-- ^ (Locally) required definitions.
3538
}
3639

3740
-- NOTE(flupe):
@@ -44,6 +47,7 @@ initState :: [QName] -> CompileState
4447
initState qs = CompileState
4548
{ seenDefs = Set.fromList qs
4649
, compileQueue = Queue.fromList qs
50+
, requiredDefs = Set.empty
4751
}
4852

4953
-- | Backend compilation monad.
@@ -56,6 +60,12 @@ newtype CompileM a = Compile (StateT CompileState TCM a)
5660
-- | Require a definition to be compiled.
5761
requireDef :: QName -> CompileM ()
5862
requireDef q = Compile $ do
63+
q <- liftTCM $ canonicalName q
64+
65+
66+
-- add name to the required list
67+
modify \ s -> s { requiredDefs = Set.insert q (requiredDefs s) }
68+
5969
seen <- gets seenDefs
6070

6171
-- a name is only added to the queue if we haven't seen it yet
@@ -76,15 +86,35 @@ nextUnit = Compile $
7686
Empty -> pure Nothing
7787
Full q queue -> Just q <$ modify \s -> s { compileQueue = queue }
7888

89+
data CompiledItem a = CompiledItem
90+
{ itemName :: QName
91+
, itemDeps :: [QName]
92+
, itemValue :: a
93+
} deriving (Functor, Foldable, Traversable)
94+
95+
-- | Record the required definitions of a compilation unit.
96+
trackDeps :: CompileM a -> CompileM (a, [QName])
97+
trackDeps (Compile c) = Compile do
98+
modify \s -> s {requiredDefs = Set.empty}
99+
x <- c
100+
deps <- gets requiredDefs
101+
pure (x, Set.toList deps)
102+
79103
-- | Run the processing function as long as there are names to be compiled.
80104
compileLoop
81-
:: (Definition -> CompileM (Maybe a)) -- ^ The compilation function
105+
:: forall a. (Definition -> CompileM a) -- ^ The compilation function
82106
-> [QName] -- ^ Names to compile
83-
-> TCM [a]
107+
-> TCM [CompiledItem a]
84108
compileLoop step = evalStateT unloop . initState
85109
where
110+
loop :: CompileM [CompiledItem a]
86111
loop@(Compile unloop) = nextUnit >>= \case
87112
Nothing -> pure []
88113
Just q -> do
89-
mr <- step =<< (liftTCM $ getConstInfo q)
90-
mcons mr <$> loop
114+
(mr, deps) <- trackDeps . step =<< (liftTCM $ getConstInfo q)
115+
let item = CompiledItem
116+
{ itemName = q
117+
, itemDeps = deps
118+
, itemValue = mr
119+
}
120+
(item:) <$> loop

src/Agda2Lambox/Compile/Term.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Data.List ( elemIndex, foldl', singleton )
1212
import Data.Maybe ( fromMaybe, listToMaybe )
1313
import Data.Foldable ( foldrM )
1414

15-
import Agda.Compiler.Backend ( MonadTCState, HasOptions )
15+
import Agda.Compiler.Backend ( MonadTCState, HasOptions, canonicalName )
1616
import Agda.Compiler.Backend ( getConstInfo, theDef, pattern Datatype, dataMutual )
1717
import Agda.Syntax.Abstract.Name ( ModuleName(..), QName(..) )
1818
import Agda.Syntax.Builtin ( builtinNat, builtinZero, builtinSuc )
@@ -99,20 +99,23 @@ compileTermC = \case
9999
-- - they cannot be propositions.
100100
-- - they cannot be types.
101101
TDef qn -> do
102+
qn <- liftTCM $ canonicalName qn
102103
CompileEnv{mutuals, boundVars} <- ask
103104
case qn `elemIndex` mutuals of
104105
Nothing -> do lift $ requireDef qn
105106
pure $ LConst $ qnameToKName qn
106107
Just i -> pure $ LRel $ i + boundVars
107108

108109
TCon q -> do
110+
q <- liftTCM $ canonicalName q
109111
lift $ requireDef q
110112
liftTCM $ toConApp q []
111113

112114
-- TODO: maybe not ignore seq? (c.f. issue #12)
113115
TApp (TPrim PSeq) args -> compileTermC (last args)
114116

115117
TApp (TCon q) args -> do
118+
q <- liftTCM $ canonicalName q
116119
lift $ requireDef q
117120
traverse compileTermC args
118121
>>= liftTCM . toConApp q
@@ -175,6 +178,7 @@ compileLitPattern = \case
175178
compileCaseType :: CaseType -> C LBox.Inductive
176179
compileCaseType = \case
177180
CTData qn -> do
181+
qn <- liftTCM $ canonicalName qn
178182
lift $ requireDef qn
179183
liftTCM $ toInductive qn
180184
CTNat -> do

src/Main.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ agda2lambox = Backend backend
110110
moduleSetup
111111
:: Options -> IsMain -> TopLevelModuleName -> Maybe FilePath
112112
-> TCM (Recompile ModuleEnv ModuleRes)
113-
moduleSetup _ _ m _ = do
113+
moduleSetup _ NotMain m _ = pure $ Skip ()
114+
moduleSetup _ IsMain m _ = do
114115
setScope . iInsideScope =<< curIF
115116
pure $ Recompile ()
116117

0 commit comments

Comments
 (0)