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
checkCompleteGrammar gr (a,abs) mo
_ -> return mo
infos <- checkErr $ topoSortJments mo
foldM updateCheckInfo mo infos
infoss <- checkErr $ topoSortJments2 mo
foldM updateCheckInfos mo infoss
where
updateCheckInfos mo0 = commitCheck . foldM updateCheckInfo mo0
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)})
-- check if restricted inheritance modules are still coherent

View File

@@ -43,7 +43,7 @@ module GF.Data.Operations (-- * misc functions
combinations,
-- * topological sorting with test of cyclicity
topoTest,
topoTest, topoTest2,
-- * the generic fix point iterator
iterFix,
@@ -60,7 +60,7 @@ module GF.Data.Operations (-- * misc functions
) where
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 Data.Map (Map)
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 = 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
iterFix :: Eq a => ([a] -> [a]) -> [a] -> [a]
iterFix more start = iter start start

View File

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

View File

@@ -568,10 +568,20 @@ allDependencies ism b =
topoSortJments :: SourceModule -> Err [(Ident,Info)]
topoSortJments (m,mi) = do
is <- either
return
return
(\cyc -> Bad (render (text "circular definitions:" <+> fsep (map ppIdent (head cyc)))))
(topoTest (allDependencies (==m) (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
pSeq p1 p2 =

View File

@@ -16,7 +16,7 @@ module GF.Infra.CheckM
(Check, CheckResult, Message, runCheck,
checkError, checkCond, checkWarn, checkWarnings, checkAccumError,
checkErr, checkIn, checkMap, checkMapRecover,
accumulateError
accumulateError, commitCheck
) where
import GF.Data.Operations
@@ -75,6 +75,18 @@ accumulateError :: (a -> Check a) -> a -> Check a
accumulateError chk 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
runCheck :: Check a -> Err (a,String)
runCheck c =
@@ -92,7 +104,7 @@ checkMap f map = do xs <- mapM (\(k,v) -> do v <- f k v
return (Map.fromAscList xs)
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
{-
checkMapRecover f mp = do