summaryrefslogtreecommitdiff
path: root/src-3.0/GF/GFCC/CheckGFCC.hs
diff options
context:
space:
mode:
authoraarne <aarne@cs.chalmers.se>2008-05-21 09:26:44 +0000
committeraarne <aarne@cs.chalmers.se>2008-05-21 09:26:44 +0000
commit055c0d0d5a5bb0dc75904fe53df7f2e4f5732a8f (patch)
tree0e63fb68c69c8f6ad0f78893c63420f0a3600e1c /src-3.0/GF/GFCC/CheckGFCC.hs
parent915a1de71783ab8446b1af9e72c7ba7dfbc12d3f (diff)
GF/src is now for 2.9, and the new sources are in src-3.0 - keep it this way until the release of GF 3
Diffstat (limited to 'src-3.0/GF/GFCC/CheckGFCC.hs')
-rw-r--r--src-3.0/GF/GFCC/CheckGFCC.hs186
1 files changed, 186 insertions, 0 deletions
diff --git a/src-3.0/GF/GFCC/CheckGFCC.hs b/src-3.0/GF/GFCC/CheckGFCC.hs
new file mode 100644
index 000000000..d59dba1a9
--- /dev/null
+++ b/src-3.0/GF/GFCC/CheckGFCC.hs
@@ -0,0 +1,186 @@
+module GF.GFCC.CheckGFCC (checkGFCC, checkGFCCio, checkGFCCmaybe) where
+
+import GF.GFCC.CId
+import GF.GFCC.Macros
+import GF.GFCC.DataGFCC
+import GF.Data.ErrM
+
+import qualified Data.Map as Map
+import Control.Monad
+import Debug.Trace
+
+checkGFCCio :: GFCC -> IO GFCC
+checkGFCCio gfcc = case checkGFCC gfcc of
+ Ok (gc,b) -> do
+ putStrLn $ if b then "OK" else "Corrupted GFCC"
+ return gc
+ Bad s -> do
+ putStrLn s
+ error "building GFCC failed"
+
+---- needed in old Custom
+checkGFCCmaybe :: GFCC -> Maybe GFCC
+checkGFCCmaybe gfcc = case checkGFCC gfcc of
+ Ok (gc,b) -> return gc
+ Bad s -> Nothing
+
+checkGFCC :: GFCC -> Err (GFCC,Bool)
+checkGFCC gfcc = do
+ (cs,bs) <- mapM (checkConcrete gfcc)
+ (Map.assocs (concretes gfcc)) >>= return . unzip
+ return (gfcc {concretes = Map.fromAscList cs}, and bs)
+
+
+-- errors are non-fatal; replace with 'fail' to change this
+msg s = trace s (return ())
+
+andMapM :: Monad m => (a -> m Bool) -> [a] -> m Bool
+andMapM f xs = mapM f xs >>= return . and
+
+labelBoolErr :: String -> Err (x,Bool) -> Err (x,Bool)
+labelBoolErr ms iob = do
+ (x,b) <- iob
+ if b then return (x,b) else (msg ms >> return (x,b))
+
+
+checkConcrete :: GFCC -> (CId,Concr) -> Err ((CId,Concr),Bool)
+checkConcrete gfcc (lang,cnc) =
+ labelBoolErr ("happened in language " ++ printCId lang) $ do
+ (rs,bs) <- mapM checkl (Map.assocs (lins cnc)) >>= return . unzip
+ return ((lang,cnc{lins = Map.fromAscList rs}),and bs)
+ where
+ checkl = checkLin gfcc lang
+
+checkLin :: GFCC -> CId -> (CId,Term) -> Err ((CId,Term),Bool)
+checkLin gfcc lang (f,t) =
+ labelBoolErr ("happened in function " ++ printCId f) $ do
+ (t',b) <- checkTerm (lintype gfcc lang f) t --- $ inline gfcc lang t
+ return ((f,t'),b)
+
+inferTerm :: [CType] -> Term -> Err (Term,CType)
+inferTerm args trm = case trm of
+ K _ -> returnt str
+ C i -> returnt $ ints i
+ V i -> do
+ testErr (i < length args) ("too large index " ++ show i)
+ returnt $ args !! i
+ S ts -> do
+ (ts',tys) <- mapM infer ts >>= return . unzip
+ let tys' = filter (/=str) tys
+ testErr (null tys')
+ ("expected Str in " ++ show trm ++ " not " ++ unwords (map show tys'))
+ return (S ts',str)
+ R ts -> do
+ (ts',tys) <- mapM infer ts >>= return . unzip
+ return $ (R ts',tuple tys)
+ P t u -> do
+ (t',tt) <- infer t
+ (u',tu) <- infer u
+ case tt of
+ R tys -> case tu of
+ R vs -> infer $ foldl P t' [P u' (C i) | i <- [0 .. length vs - 1]]
+ --- R [v] -> infer $ P t v
+ --- R (v:vs) -> infer $ P (head tys) (R vs)
+
+ C i -> do
+ testErr (i < length tys)
+ ("required more than " ++ show i ++ " fields in " ++ show (R tys))
+ return (P t' u', tys !! i) -- record: index must be known
+ _ -> do
+ let typ = head tys
+ testErr (all (==typ) tys) ("different types in table " ++ show trm)
+ return (P t' u', typ) -- table: types must be same
+ _ -> Bad $ "projection from " ++ show t ++ " : " ++ show tt
+ FV [] -> returnt tm0 ----
+ FV (t:ts) -> do
+ (t',ty) <- infer t
+ (ts',tys) <- mapM infer ts >>= return . unzip
+ testErr (all (eqType ty) tys) ("different types in variants " ++ show trm)
+ return (FV (t':ts'),ty)
+ W s r -> infer r
+ _ -> Bad ("no type inference for " ++ show trm)
+ where
+ returnt ty = return (trm,ty)
+ infer = inferTerm args
+
+checkTerm :: LinType -> Term -> Err (Term,Bool)
+checkTerm (args,val) trm = case inferTerm args trm of
+ Ok (t,ty) -> if eqType ty val
+ then return (t,True)
+ else do
+ msg ("term: " ++ show trm ++
+ "\nexpected type: " ++ show val ++
+ "\ninferred type: " ++ show ty)
+ return (t,False)
+ Bad s -> do
+ msg s
+ return (trm,False)
+
+eqType :: CType -> CType -> Bool
+eqType inf exp = case (inf,exp) of
+ (C k, C n) -> k <= n -- only run-time corr.
+ (R rs,R ts) -> length rs == length ts && and [eqType r t | (r,t) <- zip rs ts]
+ (TM _, _) -> True ---- for variants [] ; not safe
+ _ -> inf == exp
+
+-- should be in a generic module, but not in the run-time DataGFCC
+
+type CType = Term
+type LinType = ([CType],CType)
+
+tuple :: [CType] -> CType
+tuple = R
+
+ints :: Int -> CType
+ints = C
+
+str :: CType
+str = S []
+
+lintype :: GFCC -> CId -> CId -> LinType
+lintype gfcc lang fun = case typeSkeleton (lookType gfcc fun) of
+ (cs,c) -> (map vlinc cs, linc c) ---- HOAS
+ where
+ linc = lookLincat gfcc lang
+ vlinc (0,c) = linc c
+ vlinc (i,c) = case linc c of
+ R ts -> R (ts ++ replicate i str)
+
+inline :: GFCC -> CId -> Term -> Term
+inline gfcc lang t = case t of
+ F c -> inl $ look c
+ _ -> composSafeOp inl t
+ where
+ inl = inline gfcc lang
+ look = lookLin gfcc lang
+
+composOp :: Monad m => (Term -> m Term) -> Term -> m Term
+composOp f trm = case trm of
+ R ts -> liftM R $ mapM f ts
+ S ts -> liftM S $ mapM f ts
+ FV ts -> liftM FV $ mapM f ts
+ P t u -> liftM2 P (f t) (f u)
+ W s t -> liftM (W s) $ f t
+ _ -> return trm
+
+composSafeOp :: (Term -> Term) -> Term -> Term
+composSafeOp f = maybe undefined id . composOp (return . f)
+
+-- from GF.Data.Oper
+
+maybeErr :: String -> Maybe a -> Err a
+maybeErr s = maybe (Bad s) Ok
+
+testErr :: Bool -> String -> Err ()
+testErr cond msg = if cond then return () else Bad msg
+
+errVal :: a -> Err a -> a
+errVal a = err (const a) id
+
+errIn :: String -> Err a -> Err a
+errIn msg = err (\s -> Bad (s ++ "\nOCCURRED IN\n" ++ msg)) return
+
+err :: (String -> b) -> (a -> b) -> Err a -> b
+err d f e = case e of
+ Ok a -> f a
+ Bad s -> d s