1
0
forked from GitHub/gf-core
Files
gf-core/src/compiler/GF/Grammar/Analyse.hs
hallgren 3814841d7d Eliminate mutual dependencies between the GF compiler and the PGF library
+ References to modules under src/compiler have been eliminated from the PGF
  library (under src/runtime/haskell). Only two functions had to be moved (from
  GF.Data.Utilities to PGF.Utilities) to make this possible, other apparent
  dependencies turned out to be vacuous.

+ In gf.cabal, the GF executable no longer directly depends on the PGF library
  source directory, but only on the exposed library modules. This means that
  there is less duplication in gf.cabal and that the 30 modules in the
  PGF library will no longer be compiled twice while building GF.

  To make this possible, additional PGF library modules have been exposed, even
  though they should probably be considered for internal use only. They could
  be collected in a PGF.Internal module, or marked as "unstable", to make
  this explicit.

+ Also, by using the -fwarn-unused-imports flag, ~220 redundant imports were
  found and removed, reducing the total number of imports by ~15%.
2013-11-05 13:11:10 +00:00

155 lines
5.2 KiB
Haskell

module GF.Grammar.Analyse (
stripSourceGrammar,
constantDepsTerm,
sizeTerm,
sizeConstant,
sizesModule,
sizesGrammar,
printSizesGrammar
) where
import GF.Grammar.Grammar
import GF.Infra.Ident
--import GF.Infra.Option ---
import GF.Grammar.Macros
import GF.Grammar.Lookup
import GF.Data.Operations
import qualified Data.Map as Map
import Data.List (nub)
--import Debug.Trace
stripSourceGrammar :: SourceGrammar -> SourceGrammar
stripSourceGrammar sgr = mGrammar [(i, m{jments = Map.map stripInfo (jments m)}) | (i,m) <- modules sgr]
stripInfo :: Info -> Info
stripInfo i = case i of
AbsCat _ -> i
AbsFun mt mi me mb -> AbsFun mt mi Nothing mb
ResParam mp mt -> ResParam mp Nothing
ResValue lt -> i ----
ResOper mt md -> ResOper mt Nothing
ResOverload is fs -> ResOverload is [(lty, L loc (EInt 0)) | (lty,L loc _) <- fs]
CncCat mty mte _ mtf mpmcfg -> CncCat mty Nothing Nothing Nothing Nothing
CncFun mict mte mtf mpmcfg -> CncFun mict Nothing Nothing Nothing
AnyInd b f -> i
constantsInTerm :: Term -> [QIdent]
constantsInTerm = nub . consts where
consts t = case t of
Q c -> [c]
QC c -> [c]
_ -> collectOp consts t
constantDeps :: SourceGrammar -> QIdent -> Err [QIdent]
constantDeps sgr f = return $ nub $ iterFix more start where
start = constants f
more = concatMap constants
constants c = (c :) $ errVal [] $ do
ts <- termsOfConstant sgr c
return $ concatMap constantsInTerm ts
getIdTerm :: Term -> Err QIdent
getIdTerm t = case t of
Q i -> return i
QC i -> return i
P (Vr r) l -> return (r,label2ident l) --- needed if term is received from parser
_ -> Bad ("expected qualified constant, not " ++ show t)
constantDepsTerm :: SourceGrammar -> Term -> Err [Term]
constantDepsTerm sgr t = do
i <- getIdTerm t
cs <- constantDeps sgr i
return $ map Q cs --- losing distinction Q/QC
termsOfConstant :: SourceGrammar -> QIdent -> Err [Term]
termsOfConstant sgr c = case lookupOverload sgr c of
Ok tts -> return $ concat [[ty,tr] | (_,(ty,tr)) <- tts]
_ -> return $
[ty | Ok ty <- [lookupResType sgr c]] ++ -- type sig may be missing
[ty | Ok ty <- [lookupResDef sgr c]]
sizeConstant :: SourceGrammar -> Term -> Int
sizeConstant sgr t = err (const 0) id $ do
c <- getIdTerm t
fmap (sum . map sizeTerm) $ termsOfConstant sgr c
-- the number of constructors in a term, ignoring position information and unnecessary types
-- ground terms count as 1, i.e. as "one work" each
sizeTerm :: Term -> Int
sizeTerm t = case t of
App c a -> sizeTerm c + sizeTerm a -- app nodes don't count
Abs _ _ b -> 2 + sizeTerm b
Prod _ _ a b -> 2 + sizeTerm a + sizeTerm b
S c a -> 1 + sizeTerm c + sizeTerm a
Table a c -> 1 + sizeTerm a + sizeTerm c
ExtR a c -> 1 + sizeTerm a + sizeTerm c
R r -> 1 + sum [1 + sizeTerm a | (_,(_,a)) <- r] -- label counts as 1, type ignored
RecType r -> 1 + sum [1 + sizeTerm a | (_,a) <- r] -- label counts as 1
P t i -> 2 + sizeTerm t
T _ cc -> 1 + sum [1 + sizeTerm (patt2term p) + sizeTerm v | (p,v) <- cc]
V ty cc -> 1 + sizeTerm ty + sum [1 + sizeTerm v | v <- cc]
Let (x,(mt,a)) b -> 2 + maybe 0 sizeTerm mt + sizeTerm a + sizeTerm b
C s1 s2 -> 1 + sizeTerm s1 + sizeTerm s2
Glue s1 s2 -> 1 + sizeTerm s1 + sizeTerm s2
Alts t aa -> 1 + sizeTerm t + sum [sizeTerm p + sizeTerm v | (p,v) <- aa]
FV ts -> 1 + sum (map sizeTerm ts)
Strs tt -> 1 + sum (map sizeTerm tt)
_ -> 1
-- the size of a judgement
sizeInfo :: Info -> Int
sizeInfo i = case i of
AbsCat (Just (L _ co)) -> 1 + sum [1 + sizeTerm ty | (_,_,ty) <- co]
AbsFun mt mi me mb -> 1 + msize mt +
sum [sum (map (sizeTerm . patt2term) ps) + sizeTerm t | Just es <- [me], L _ (ps,t) <- es]
ResParam mp mt ->
1 + sum [1 + sum [1 + sizeTerm ty | (_,_,ty) <- co] | Just (L _ ps) <- [mp], (_,co) <- ps]
ResValue lt -> 0
ResOper mt md -> 1 + msize mt + msize md
ResOverload is fs -> 1 + sum [sizeTerm ty + sizeTerm tr | (L _ ty, L _ tr) <- fs]
CncCat mty _ _ _ _ -> 1 + msize mty -- ignoring lindef, linref and printname
CncFun mict mte mtf _ -> 1 + msize mte -- ignoring type and printname
AnyInd b f -> -1 -- just to ignore these in the size
_ -> 0
where
msize mt = case mt of
Just (L _ t) -> sizeTerm t
_ -> 0
-- the size of a module
sizeModule :: SourceModule -> Int
sizeModule = fst . sizesModule
sizesModule :: SourceModule -> (Int, [(Ident,Int)])
sizesModule (_,m) =
let
js = Map.toList (jments m)
tb = [(i,k) | (i,j) <- js, let k = sizeInfo j, k >= 0]
in (length tb + sum (map snd tb),tb)
-- the size of a grammar
sizeGrammar :: SourceGrammar -> Int
sizeGrammar = fst . sizesGrammar
sizesGrammar :: SourceGrammar -> (Int,[(Ident,(Int,[(Ident,Int)]))])
sizesGrammar g =
let
ms = modules g
mz = [(i,sizesModule m) | m@(i,j) <- ms]
in (length mz + sum (map (fst . snd) mz), mz)
printSizesGrammar :: SourceGrammar -> String
printSizesGrammar g = unlines $
("total" +++ show s):
[showIdent m +++ "total" +++ show i ++++
unlines [indent 2 (showIdent j +++ show k) | (j,k) <- js]
| (m,(i,js)) <- sg
]
where
(s,sg) = sizesGrammar g