faster and correct dependency checking

This commit is contained in:
Krasimir Angelov
2026-01-02 08:20:52 +01:00
parent d18969a6fb
commit 0a33204ee4
5 changed files with 31 additions and 52 deletions
+3 -3
View File
@@ -53,8 +53,8 @@ checkModule opts cwd sgr mo@(m,mi) = do
abs <- lookupModule gr a abs <- lookupModule gr a
checkCompleteGrammar opts cwd gr (a,abs) mo checkCompleteGrammar opts cwd gr (a,abs) mo
_ -> return mo _ -> return mo
infoss <- checkInModule cwd mi NoLoc empty $ topoSortJments2 mo infos <- checkInModule cwd mi NoLoc empty $ topoSortJments mo
foldM (foldM (checkInfo opts cwd sgr)) mo infoss foldM (checkInfo opts cwd sgr) mo infos
-- check if restricted inheritance modules are still coherent -- check if restricted inheritance modules are still coherent
-- i.e. that the defs of remaining names don't depend on omitted names -- i.e. that the defs of remaining names don't depend on omitted names
@@ -71,7 +71,7 @@ checkRestrictedInheritance cwd sgr (name,mo) = checkInModule cwd mo NoLoc empty
let incld c = Set.member c (Set.fromList incl) let incld c = Set.member c (Set.fromList incl)
let illegal c = Set.member c (Set.fromList excl) let illegal c = Set.member c (Set.fromList excl)
let illegals = [(f,is) | let illegals = [(f,is) |
(f,cs) <- allDeps, incld f, let is = filter illegal cs, not (null is)] (f,_,cs) <- allDeps, incld f, let is = filter illegal cs, not (null is)]
case illegals of case illegals of
[] -> return () [] -> return ()
cs -> checkWarn ("In inherited module" <+> i <> ", dependence of excluded constants:" $$ cs -> checkWarn ("In inherited module" <+> i <> ", dependence of excluded constants:" $$
-24
View File
@@ -35,9 +35,6 @@ module GF.Data.Operations (
prBracket, prArgList, prSemicList, prCurlyList, restoreEscapes, prBracket, prArgList, prSemicList, prCurlyList, restoreEscapes,
numberedParagraphs, prConjList, prIfEmpty, wrapLines, numberedParagraphs, prConjList, prIfEmpty, wrapLines,
-- ** Topological sorting
topoTest, topoTest2,
-- ** Misc -- ** Misc
readIntArg, readIntArg,
iterFix, chunks, iterFix, chunks,
@@ -53,7 +50,6 @@ import Control.Monad (liftM,liftM2) --,ap
import Control.Monad.Fix import Control.Monad.Fix
import GF.Data.ErrM import GF.Data.ErrM
import GF.Data.Relation
import qualified Control.Monad.Fail as Fail import qualified Control.Monad.Fail as Fail
infixr 5 +++ infixr 5 +++
@@ -188,26 +184,6 @@ wrapLines n s@(c:cs) =
l = length w l = length w
_ -> s -- give up!! _ -> s -- give up!!
-- | Topological sorting with test of cyclicity
topoTest :: Ord a => [(a,[a])] -> Either [a] [[a]]
topoTest = topologicalSort . mkRel'
-- | Topological sorting with test of cyclicity, new version /TH 2012-06-26
topoTest2 :: Ord a => [(a,[a])] -> Either [[a]] [[a]]
topoTest2 g0 = maybe (Right cycles) Left (tsort g)
where
g = g0++[(n,[])|n<-nub (concatMap snd g0)\\map fst g0]
cycles = findCycles (mkRel' g)
tsort nes =
case partition (null.snd) nes of
([],[]) -> Just []
([],_) -> Nothing
(ns,rest) -> (leaves:) `fmap` tsort [(n,es \\ leaves) | (n,es)<-rest]
where leaves = map fst ns
-- | Fix point iterator (for computing e.g. transitive closures or reachability) -- | Fix point iterator (for computing e.g. transitive closures or reachability)
iterFix :: Eq a => ([a] -> [a]) -> [a] -> [a] iterFix :: Eq a => ([a] -> [a]) -> [a] -> [a]
iterFix more start = iter start start iterFix more start = iter start start
+6 -4
View File
@@ -77,6 +77,7 @@ import GF.Data.Operations
import PGF2(BindType(..),PGF) import PGF2(BindType(..),PGF)
import PGF2.Transactions(LIndex,LVar,LParam(..),PArg(..),Symbol(..),Rule(..)) import PGF2.Transactions(LIndex,LVar,LParam(..),PArg(..),Symbol(..),Rule(..))
import Data.Graph
import Data.Array.IArray(Array) import Data.Array.IArray(Array)
import Data.Array.Unboxed(UArray) import Data.Array.Unboxed(UArray)
import qualified Data.Map as Map import qualified Data.Map as Map
@@ -276,10 +277,11 @@ isCompleteModule m = mstatus m == MSComplete && mtype m /= MTInterface
-- | all abstract modules sorted from least to most dependent -- | all abstract modules sorted from least to most dependent
allAbstracts :: Grammar -> [ModuleName] allAbstracts :: Grammar -> [ModuleName]
allAbstracts gr = allAbstracts gr =
case topoTest [(i,extends m) | (i,m) <- modules gr, mtype m == MTAbstract] of let scc = stronglyConnComp [(mn,mn,extends mo) | (mn,mo) <- modules gr, mtype mo == MTAbstract]
Left is -> is in case [mns | CyclicSCC mns <- scc] of
Right cycles -> error $ render ("Cyclic abstract modules:" <+> vcat (map hsep cycles)) [] -> [mn | AcyclicSCC mn <- scc]
cycles -> error $ render ("Cyclic abstract modules:" <+> vcat (map hsep cycles))
-- | the last abstract in dependency order (head of list) -- | the last abstract in dependency order (head of list)
greatestAbstract :: Grammar -> Maybe ModuleName greatestAbstract :: Grammar -> Maybe ModuleName
+22 -20
View File
@@ -28,10 +28,11 @@ import GF.Grammar.Printer
import Control.Monad.Identity(Identity(..)) import Control.Monad.Identity(Identity(..))
import qualified Data.Traversable as T(mapM) import qualified Data.Traversable as T(mapM)
import qualified Data.Map as Map import qualified Data.Map as Map
import Control.Monad (liftM, liftM2, liftM3) import Control.Monad (liftM, liftM2, liftM3, forM)
import Data.List (sortBy,nub) import Data.List (sortBy,nub)
import Data.Monoid import Data.Monoid
import GF.Text.Pretty(render,(<+>),hsep,fsep) import Data.Graph
import GF.Text.Pretty(render,(<+>),($$),hsep,fsep,vcat,nest)
import qualified Control.Monad.Fail as Fail import qualified Control.Monad.Fail as Fail
-- ** Functions for constructing and analysing source code terms. -- ** Functions for constructing and analysing source code terms.
@@ -538,16 +539,25 @@ sortRec = sortBy ordLabel where
-- | dependency check, detecting circularities and returning topo-sorted list -- | dependency check, detecting circularities and returning topo-sorted list
allDependencies :: (ModuleName -> Bool) -> Map.Map Ident Info -> [(Ident,[Ident])] allDependencies :: (ModuleName -> Bool) -> Map.Map Ident Info -> [(Ident,Info,[Ident])]
allDependencies ism b = allDependencies ism b =
[(f, nub (concatMap opty (pts i))) | (f,i) <- Map.toList b] [(f, i, nub (concatMap opty (pts i))) | (f,i) <- Map.toList b]
where where
opersIn t = case t of opersIn t = case t of
Q (n,c) | ism n -> [c] Q (n,c) | ism n -> [c]
QC (n,c) | ism n -> [c] QC (n,c) | ism n -> [c]
EPatt _ _ p -> opersInPatt p
T _ cs -> mconcatMap (\(p,t) -> opersInPatt p ++ opersIn t) cs
_ -> collectOp opersIn t _ -> collectOp opersIn t
opersInPatt p = case p of
PTilde t -> opersIn t
PM (n,c) | ism n -> [c]
_ -> collectPattOp opersInPatt p
opty (Just (L _ ty)) = opersIn ty opty (Just (L _ ty)) = opersIn ty
opty _ = [] opty _ = []
pts i = case i of pts i = case i of
ResOper pty pt -> [pty,pt] ResOper pty pt -> [pty,pt]
ResOverload _ tyts -> concat [[Just ty, Just tr] | (ty,tr) <- tyts] ResOverload _ tyts -> concat [[Just ty, Just tr] | (ty,tr) <- tyts]
@@ -560,22 +570,14 @@ allDependencies ism b =
topoSortJments :: ErrorMonad m => SourceModule -> m [(Ident,Info)] topoSortJments :: ErrorMonad m => SourceModule -> m [(Ident,Info)]
topoSortJments (m,mi) = do topoSortJments (m,mi) = do
is <- either let sccs = stronglyConnComp (map toNode (allDependencies (==m) (jments mi)))
return cycles = [map fst jmts | CyclicSCC jmts <- sccs]
(\cyc -> raise (render ("circular definitions:" <+> fsep (head cyc)))) case cycles of
(topoTest (allDependencies (==m) (jments mi))) [] -> return [jmt | AcyclicSCC jmt <- sccs]
return (reverse [(i,info) | i <- is, Just info <- [Map.lookup i (jments mi)]]) _ -> raise (render ("circular definitions:" $$
nest 3 (vcat (map fsep cycles))))
topoSortJments2 :: ErrorMonad m => SourceModule -> m [[(Ident,Info)]] where
topoSortJments2 (m,mi) = do toNode (id,info,deps) = ((id,info),id,deps)
iss <- either
return
(\cyc -> raise (render ("circular definitions:"
<+> fsep (head cyc))))
(topoTest2 (allDependencies (==m) (jments mi)))
return
[[(i,info) | i<-is,Just info<-[Map.lookup i (jments mi)]] | is<-iss]
mkStrs p = case p of mkStrs p = case p of
PAlt a b -> do PAlt a b -> do
-1
View File
@@ -20,7 +20,6 @@ import GF.Grammar.CFG
--import GF.Infra.Ident (Ident) --import GF.Infra.Ident (Ident)
import GF.Data.Graph import GF.Data.Graph
--import GF.Data.Relation
import GF.Speech.FiniteState import GF.Speech.FiniteState
--import GF.Speech.CFG --import GF.Speech.CFG