1
0
forked from GitHub/gf-core

Report many type errors instead of stopping after the first one

In GF.Compile.CheckGrammar, use a new topological sorting function that
groups independent judgements, allowing them all to be checked before
continuing or reporting errors.
This commit is contained in:
hallgren
2012-06-26 14:46:18 +00:00
parent 852d923786
commit 5b577baf02
5 changed files with 47 additions and 9 deletions

View File

@@ -53,11 +53,13 @@ checkModule opts mos mo@(m,mi) = do
abs <- checkErr $ lookupModule gr a abs <- checkErr $ lookupModule gr a
checkCompleteGrammar gr (a,abs) mo checkCompleteGrammar gr (a,abs) mo
_ -> return mo _ -> return mo
infos <- checkErr $ topoSortJments mo infoss <- checkErr $ topoSortJments2 mo
foldM updateCheckInfo mo infos foldM updateCheckInfos mo infoss
where where
updateCheckInfos mo0 = commitCheck . foldM updateCheckInfo mo0
updateCheckInfo mo@(m,mi) (i,info) = do updateCheckInfo mo@(m,mi) (i,info) = do
info <- checkInfo opts mos mo i info info <- accumulateError (checkInfo opts mos mo i) info
return (m,mi{jments=updateTree (i,info) (jments mi)}) return (m,mi{jments=updateTree (i,info) (jments mi)})
-- check if restricted inheritance modules are still coherent -- check if restricted inheritance modules are still coherent

View File

@@ -43,7 +43,7 @@ module GF.Data.Operations (-- * misc functions
combinations, combinations,
-- * topological sorting with test of cyclicity -- * topological sorting with test of cyclicity
topoTest, topoTest, topoTest2,
-- * the generic fix point iterator -- * the generic fix point iterator
iterFix, iterFix,
@@ -60,7 +60,7 @@ module GF.Data.Operations (-- * misc functions
) where ) where
import Data.Char (isSpace, toUpper, isSpace, isDigit) import Data.Char (isSpace, toUpper, isSpace, isDigit)
import Data.List (nub, sortBy, sort, deleteBy, nubBy) import Data.List (nub, sortBy, sort, deleteBy, nubBy, partition, (\\))
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Map (Map) import Data.Map (Map)
import Control.Monad (liftM,liftM2, MonadPlus, mzero, mplus) import Control.Monad (liftM,liftM2, MonadPlus, mzero, mplus)
@@ -267,6 +267,20 @@ combinations t = case t of
topoTest :: Ord a => [(a,[a])] -> Either [a] [[a]] topoTest :: Ord a => [(a,[a])] -> Either [a] [[a]]
topoTest = topologicalSort . mkRel' topoTest = topologicalSort . mkRel'
-- | topological sorting with test of cyclicity, new version /TH 2012-06-26
topoTest2 :: Ord a => [(a,[a])] -> Either [[a]] [[a]]
topoTest2 g = maybe (Right cycles) Left (tsort g)
where
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
-- | the generic fix point iterator -- | the generic fix point iterator
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

View File

@@ -23,7 +23,7 @@ module GF.Data.Relation (Rel, mkRel, mkRel'
, isTransitive, isReflexive, isSymmetric , isTransitive, isReflexive, isSymmetric
, isEquivalence , isEquivalence
, isSubRelationOf , isSubRelationOf
, topologicalSort) where , topologicalSort, findCycles) where
import Data.Foldable (toList) import Data.Foldable (toList)
import Data.List import Data.List

View File

@@ -568,10 +568,20 @@ allDependencies ism b =
topoSortJments :: SourceModule -> Err [(Ident,Info)] topoSortJments :: SourceModule -> Err [(Ident,Info)]
topoSortJments (m,mi) = do topoSortJments (m,mi) = do
is <- either is <- either
return return
(\cyc -> Bad (render (text "circular definitions:" <+> fsep (map ppIdent (head cyc))))) (\cyc -> Bad (render (text "circular definitions:" <+> fsep (map ppIdent (head cyc)))))
(topoTest (allDependencies (==m) (jments mi))) (topoTest (allDependencies (==m) (jments mi)))
return (reverse [(i,info) | i <- is, Ok info <- [lookupTree showIdent i (jments mi)]]) return (reverse [(i,info) | i <- is, Ok info <- [lookupTree showIdent i (jments mi)]])
topoSortJments2 :: SourceModule -> Err [[(Ident,Info)]]
topoSortJments2 (m,mi) = do
iss <- either
return
(\cyc -> fail (render (text "circular definitions:"
<+> fsep (map ppIdent (head cyc)))))
(topoTest2 (allDependencies (==m) (jments mi)))
return
[[(i,info) | i<-is,Ok info<-[lookupTree showIdent i (jments mi)]] | is<-iss]
{- {-
-- | Smart constructor for PSeq -- | Smart constructor for PSeq
pSeq p1 p2 = pSeq p1 p2 =

View File

@@ -16,7 +16,7 @@ module GF.Infra.CheckM
(Check, CheckResult, Message, runCheck, (Check, CheckResult, Message, runCheck,
checkError, checkCond, checkWarn, checkWarnings, checkAccumError, checkError, checkCond, checkWarn, checkWarnings, checkAccumError,
checkErr, checkIn, checkMap, checkMapRecover, checkErr, checkIn, checkMap, checkMapRecover,
accumulateError accumulateError, commitCheck
) where ) where
import GF.Data.Operations import GF.Data.Operations
@@ -75,6 +75,18 @@ accumulateError :: (a -> Check a) -> a -> Check a
accumulateError chk a = accumulateError chk a =
handle' (chk a) $ \ msg -> do checkAccumError msg; return a handle' (chk a) $ \ msg -> do checkAccumError msg; return a
-- | Turn accumulated errors into a fatal error
commitCheck :: Check a -> Check a
commitCheck c =
Check $ \ ctxt msgs0@(es0,ws0) ->
case unCheck c ctxt ([],[]) of
(([],ws),Success v) -> ((es0,ws++ws0),Success v)
(msgs ,Success _) -> bad msgs0 msgs
((es,ws),Fail e) -> bad msgs0 ((e:es),ws)
where
bad (es0,ws0) (es,ws) = ((es0,ws++ws0),Fail (list es))
list = vcat . reverse
-- | Run an error check, report errors and warnings -- | Run an error check, report errors and warnings
runCheck :: Check a -> Err (a,String) runCheck :: Check a -> Err (a,String)
runCheck c = runCheck c =
@@ -92,7 +104,7 @@ checkMap f map = do xs <- mapM (\(k,v) -> do v <- f k v
return (Map.fromAscList xs) return (Map.fromAscList xs)
checkMapRecover :: (Ord a) => (a -> b -> Check b) -> Map.Map a b -> Check (Map.Map a b) checkMapRecover :: (Ord a) => (a -> b -> Check b) -> Map.Map a b -> Check (Map.Map a b)
checkMapRecover f mp = checkMap f' mp checkMapRecover f mp = commitCheck (checkMap f' mp)
where f' key info = accumulateError (f key) info where f' key info = accumulateError (f key) info
{- {-
checkMapRecover f mp = do checkMapRecover f mp = do