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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user