Files
gf-core/src/compiler/api/GF/Compile/GeneratePMCFG.hs
T

528 lines
21 KiB
Haskell

{-# LANGUAGE RankNTypes #-}
module GF.Compile.GeneratePMCFG
(generatePMCFG, pmcfgForm, type2fields
) where
import GF.Infra.Ident
import GF.Infra.Option
import GF.Infra.CheckM
import GF.Data.Operations
import GF.Grammar.Grammar
import GF.Grammar.Lookup
import GF.Grammar.Macros
import GF.Grammar.Predef
import GF.Grammar.Printer hiding (ppValue)
import GF.Text.Pretty hiding (empty)
import GF.Compile.Compute.Concrete hiding ( getMeta, setMeta, globals, variants )
import qualified GF.Text.Pretty as PP
import qualified Data.Map as Map
import qualified Data.Set as Set
import Control.Applicative
import Control.Monad (foldM,zipWithM,liftM,liftM2,forM,MonadPlus(..))
import Control.Monad.Fix
import Data.Maybe
import Data.List(mapAccumL,sortBy,intersperse)
import Prelude hiding ((<>))
generatePMCFG :: Options -> FilePath -> SourceGrammar -> SourceModule -> Check SourceModule
generatePMCFG opts cwd gr cmo@(cm,cmi)
| mstatus cmi == MSComplete && isModCnc cmi =
do let gr' = prependModule gr cmo
g = Gl gr' (stdPredef g)
js <- Map.traverseWithKey (addPMCFG cwd g cmi) (jments cmi)
return (cm,cmi{jments = js})
| otherwise = return cmo
addPMCFG cwd g cmi id (CncCat mty@(Just (L loc ty)) mdef mref mprn Nothing) = do
defs <- case mdef of
Nothing -> checkInModule cwd cmi loc ("Happened in the rule generation for the lindef of" <+> id) $ do
t <- mkLinDefault sgr ty
pmcfgForm g t [(Explicit,identW,Sort cStr)] ty
Just (L loc t) -> checkInModule cwd cmi loc ("Happened in the PMCFG generation for the lindef of" <+> id) $ do
pmcfgForm g t [(Explicit,identW,Sort cStr)] ty
refs <- case mref of
Nothing -> checkInModule cwd cmi loc ("Happened in the rule generation for the linref of" <+> id) $ do
t <- mkLinReference sgr ty
pmcfgForm g t [(Explicit,identW,ty)] (Sort cStr)
Just (L loc t) -> checkInModule cwd cmi loc ("Happened in the PMCFG generation for the linref of" <+> id) $ do
pmcfgForm g t [(Explicit,identW,ty)] (Sort cStr)
mprn <- case mprn of
Nothing -> return Nothing
Just (L loc prn) -> checkInModule cwd cmi loc ("Happened in the computation of the print name for" <+> id) $ do
prn <- normalForm g prn
return (Just (L loc prn))
return (CncCat mty mdef mref mprn (Just (defs,refs)))
where
Gl sgr _ = g
addPMCFG cwd g cmi id (CncFun (Just lty@(cats,cat,ctxt,ty)) mlin@(Just (L loc term)) mprn Nothing) = do
rules <- checkInModule cwd cmi loc ("Happened in the rule generation for" <+> id) $
pmcfgForm g term ctxt ty
mprn <- case mprn of
Nothing -> return Nothing
Just (L loc prn) -> checkInModule cwd cmi loc ("Happened in the computation of the print name for" <+> id) $ do
prn <- normalForm g prn
return (Just (L loc prn))
return (CncFun (Just lty) mlin mprn (Just rules))
where
Gl sgr _ = g
addPMCFG cwd g cmi id info = return info
pmcfgForm g t ctxt ty = do
let (ms,s',t',arg_params) = apply 0 Map.empty unit ctxt t []
let v = eval g [] s' t' []
(ms,_,_,fn) <- breakDown g ms unit 0 [] v ty (return []) empty
runGenM g ms [] $ do
(r,rs,v,res_params) <- fn
arg_params <- mapM params2int arg_params
res_params <- params2int res_params
lin_idx <- params2int' r rs
seq <- flatten v
qs <- quantifiers (arg_params++[res_params,lin_idx])
return (Rule qs res_params arg_params lin_idx seq)
where
Gl sgr _ = g
quantifiers params = GenM (\(Gl sgr _) k svs ms ->
k ((Set.toList . Set.fromList)
[(variable,boundsOf sgr ms variable) | LParam _ terms <- params, (factor,variable) <- terms])
svs ms)
where
boundsOf sgr ms i =
case Map.lookup (i+1) ms of
Just (Narrowing _ pty) -> case allParamValues sgr pty of
Ok ps -> length ps
Bad msg -> error msg
_ -> error (show (ppLVar i <+> "is not a free variable"))
apply d ms s [] t args = (ms,s,t,reverse args)
apply d ms s ((_,_,ty):ctxt) t args =
let (ms',s',_,t2,params) = type2metaTerm sgr d ms s 0 [] ty []
in apply (d+1) ms' s' ctxt (App t t2) (params:args)
type2fields :: SourceGrammar -> Type -> [String]
type2fields gr = map show . type2fields PP.empty
where
type2fields d (Sort s) | s == cStr = [show d]
type2fields d (RecType lbls) =
concatMap (\(lbl,ty) -> type2fields (d <+> pp lbl) ty) lbls
type2fields d (Table p q) =
let Ok ts = allParamValues gr p
in concatMap (\t -> type2fields (d <+> ppTerm Unqualified 5 t) q) ts
type2fields d _ = []
mkLinDefault :: SourceGrammar -> Type -> Check Term
mkLinDefault gr typ = liftM (Abs Explicit varStr) $ mkDefField typ
where
mkDefField ty =
case ty of
Table p t -> do t' <- mkDefField t
let T _ cs = mkWildCases t'
return $ T (TWild p) cs
Sort s | s == cStr -> return (Vr varStr)
QC p -> case lookupParamValues gr p of
Ok [] -> checkError ("no parameter values given to type" <+> ppQIdent Qualified p)
Ok (v:_) -> return v
Bad msg -> fail msg
RecType r -> do
let (ls,ts) = unzip r
ts <- mapM mkDefField ts
return $ R (zipWith assign ls ts)
_ | Just _ <- isTypeInts ty -> return $ EInt 0 -- exists in all as first val
_ -> checkError ("a field in a linearization type cannot be" <+> ty)
mkLinReference :: SourceGrammar -> Type -> Check Term
mkLinReference gr typ = do
mb_term <- mkRefField typ (Vr varStr)
return (Abs Explicit varStr (fromMaybe Empty mb_term))
where
mkRefField ty trm =
case ty of
Table pty ty -> do ps <- allParamValues gr pty
case ps of
[] -> fail (render ("no parameter values given to type" <+> pty))
(p:ps) -> mkRefField ty (S trm p)
Sort s | s == cStr -> return (Just trm)
QC p -> return Nothing
RecType rs -> traverse rs trm
_ | Just _ <- isTypeInts ty -> return Nothing
_ -> fail (render ("a field in a linearization type cannot be" <+> typ))
traverse [] trm = return Nothing
traverse ((l,ty):rs) trm = do res <- mkRefField ty (P trm l)
case res of
Just trm -> return (Just trm)
Nothing -> traverse rs trm
type2metaTerm :: SourceGrammar -> Int -> MetaVars -> Choice -> LIndex -> [(LIndex,(Ident,Type))] -> Type -> [(Value,Type)] -> (MetaVars,Choice,Int,Term,[(Value,Type)])
type2metaTerm gr d ms s r rs (Sort srt) params | srt == cStr = (ms,s,r+1,TSymCat d r rs,params)
type2metaTerm gr d ms s r rs (RecType lbls) params =
let ((ms',s',r',params'),ass) =
mapAccumL (\(ms,s,r,params) (lbl,ty) -> case lbl of
LVar j -> ((ms,s,r,params),(lbl,(Just ty,TSymVar d j)))
lbl -> let (ms',s',r',t,params') = type2metaTerm gr d ms s r rs ty params
in ((ms',s',r',params'),(lbl,(Just ty,t))))
(ms,s,r,params) lbls
in (ms',s',r',R ass,params')
type2metaTerm gr d ms s r rs (Table p q) params
| count == 1 = let (ms',s',r',t,params') = type2metaTerm gr d ms s r rs q params
in (ms',s',r+(r'-r),T (TTyped p) [(PW,t)],params')
| otherwise = let pv = varX (length rs+1)
(ms',s',r',t,params') = type2metaTerm gr d ms s r ((delta,(pv,p)):rs) q params
delta = r'-r
in (ms',s',r+delta*count,T (TTyped p) [(PV pv,t)],params')
where
count = case allParamValues gr p of
Ok ts -> length ts
Bad msg -> error msg
type2metaTerm gr d ms c r rs ty@(QC q) params =
let i = Map.size ms + 1
(c1,c2) = split c
in (Map.insert i (Narrowing c1 ty) ms,c2,r,Meta i,(VMeta i [],ty):params)
type2metaTerm gr d ms c r rs ty params
| Just n <- isTypeInts ty =
let i = Map.size ms + 1
(c1,c2) = split c
in (Map.insert i (Narrowing c1 ty) ms,c2,r,Meta i,(VMeta i [],ty):params)
breakDown g ms s r rs v (Sort sort) fn0 fn
| sort == cStr =
let fn' = do params <- fn0
v <- force v
return (r,rs,v,params)
<|>
do fn
in return (ms,r+1,fn0,fn')
breakDown g ms s r rs v (RecType lbls) fn0 fn = traverse ms r rs lbls fn0 fn
where
traverse ms r rs [] fn0 fn = return (ms,r,fn0,fn)
traverse ms r rs ((lbl,ty):lbls) fn0 fn = do (ms,r,fn0,fn) <- breakDown g ms s r rs (project v) ty fn0 fn
traverse ms r rs lbls fn0 fn
where
project (VR as) = case lookup lbl as of
Nothing -> error (render ("Missing value for label" <+> pp lbl $$
"in" <+> ppValue Unqualified 0 (VR as)))
Just v -> v
project (VFV c fvs) = VFV c (fmap project fvs)
project (VMeta i vs) = VSusp i (\v -> project (apply g v vs)) []
project (VSusp i k vs)= VSusp i (\v -> project (apply g (k v) vs)) []
project v = VP v lbl []
breakDown g ms c r rs v (Table p q) fn0 fn = do
let i = Map.size ms + 1
v2 = VMeta i []
v0 = VS v v2 []
(c1,c2) = split c
Gl gr _ = g
cnt <- fmap length $ allParamValues gr p
(ms,r',fn0,fn) <- mfix $ \(~(_,r',_,_)) ->
breakDown g (Map.insert i (Narrowing c1 p) ms) c2 r ((r'-r,(v2,p)):rs) (select v0 v v2) q fn0 fn
return (ms,r+(r'-r)*cnt,fn0,fn)
where
select v0 (VT _ env s cs) v2 = patternMatch g s v0 (map (\(p,t) -> (env,[p],[v2],t)) cs)
select v0 (VV vty tvs) v2 = vtableSelect g v0 vty tvs v2 []
select v0 (VFV i fvs) v2 = VFV i (fmap (\v1 -> select v0 v1 v2) fvs)
select v0 (VMeta i vs) v2 = VSusp i (\v -> select v0 (apply g v vs) v2) []
select v0 (VSusp i k vs) v2 = VSusp i (\v -> select v0 (apply g (k v) vs) v2) []
select v0 v1 v2 = v0
breakDown g ms s r rs v ty@(QC q) fn0 fn =
let fn0' = do params <- fn0
v <- force v
return ((v,ty):params)
fn' = do (r,rs,v',res_params) <- fn
v <- force v
return (r,rs,v',(v,ty):res_params)
in return (ms,r,fn0',fn')
breakDown g ms s r rs v ty@(App (Q q) _) fn0 fn =
let fn0' = do params <- fn0
v <- force v
return ((v,ty):params)
fn' = do (r,rs,v',res_params) <- fn
v <- force v
return (r,rs,v',(v,ty):res_params)
in return (ms,r,fn0',fn')
force (VStr s) = return (VStr s)
force (VInt n) = return (VInt n)
force (VFlt d) = return (VFlt d)
force (VSymCat d r rs) = do
rs <- mapM force_ rs
return (VSymCat d r rs)
where
force_ (factor, (v, ty)) = do
v <- force v
return (factor, (v, ty))
force (VApp c q vs) = do
vs <- mapM force vs
return (VApp c q vs)
force (VAlts def alts) = do
def <- force def
alts <- mapM force_ alts
return (VAlts def alts)
where
force_ (x,y) = do
x <- force x
y <- force y
return (x,y)
force VEmpty = return VEmpty
force (VC v1 v2) = do
v1 <- force v1
v2 <- force v2
return (VC v1 v2)
force (VMeta i vs) = do
vs <- mapM force vs
return (VMeta i vs)
force (VSusp i k vs) = do
vs <- mapM force vs
st <- getMeta i
v <- case st of
Narrowing c ty -> do v <- chooseMetaValue c ty
setMeta i (Bound undefined v)
return v
Bound _ v -> return v
g <- globals
force (apply g (k v) vs)
force (VStrs vs) = do
vs <- mapM force vs
return (VStrs vs)
force (VR as) = do
as <- mapM (\(l,v) -> fmap ((,) l) (force v)) as
return (VR as)
force v@(VPatt _ _ _) = return v
force (VFV c vs) = do
v <- variants c (unvariants vs)
force v
force v = compileError ("Cannot evaluate" <+> ppValue Unqualified 0 v)
flatten (VStr s) = return [SymKS s]
flatten (VSymCat d r rs) = do
lin_index <- params2int' r rs
return [SymCat d lin_index]
flatten (VApp _ (m,id) [])
| m == cPredef && id == cBIND = return [SymBIND]
| m == cPredef && id == cSOFT_BIND = return [SymSOFT_BIND]
| m == cPredef && id == cSOFT_SPACE = return [SymSOFT_SPACE]
| m == cPredef && id == cNonExist = return [SymNE]
| m == cPredef && id == cCAPIT = return [SymCAPIT]
| m == cPredef && id == cALL_CAPIT = return [SymALL_CAPIT]
flatten v0@(VAlts def alts) = do
def <- flatten def
alts <- forM alts $ \(alt,ps) -> do
alt <- flatten alt
ps <- to_strs ps
return (alt,ps)
return [SymKP def alts]
where
to_strs (VStrs vs) = mapM to_str vs
to_strs (VPatt _ _ p) = from_patt p
to_strs v = fail
to_str (VStr s) = return s
to_str _ = fail
from_patt (PAlt p1 p2) = liftM2 (++) (from_patt p1) (from_patt p2)
from_patt (PSeq _ _ p1 _ _ p2) = liftM2 (liftM2 (++)) (from_patt p1) (from_patt p2)
from_patt (PString s) = return [s]
from_patt (PChars cs) = return (map (:[]) cs)
from_patt _ = fail
fail = compileError ("Complex patterns are not supported in:" $$ nest 2 (ppValue Unqualified 0 v0))
flatten VEmpty = return []
flatten (VC v1 v2) = do
s1 <- flatten v1
s2 <- flatten v2
return (s1++s2)
flatten (VSusp i k vs) = do
st <- getMeta i
v <- case st of
Narrowing c ty -> do v <- chooseMetaValue c ty
setMeta i (Bound undefined v)
return v
Bound _ v -> return v
g <- globals
flatten (apply g (k v) vs)
flatten (VFV c vs) = do
v <- variants c (unvariants vs)
flatten v
flatten v = compileError ("Cannot evaluate" <+> ppValue Unqualified 0 v <+> "to a string")
params2int rs = do
(r,rs,_) <- compute rs
return (LParam r (order rs))
where
compute [] = return (0,[],1)
compute ((v,ty):params) = do
(r, rs, cnt ) <- param2int v ty
(r',rs',cnt') <- compute params
return (r*cnt'+r',combine cnt' rs rs',cnt*cnt')
params2int' r0 rs = do
(r,rs) <- compute rs
return (LParam (r0+r) (order rs))
where
compute [] = return (0,[])
compute ((cnt',(v,ty)):params) = do
(r, rs, cnt) <- param2int v ty
(r',rs') <- compute params
return (r*cnt'+r',combine cnt' rs rs')
param2int (VR as) (RecType lbls) = compute lbls
where
compute [] = return (0,[],1)
compute ((lbl,ty):lbls) = do
case lookup lbl as of
Just v -> do (r, rs ,cnt ) <- param2int v ty
(r',rs',cnt') <- compute lbls
return (r*cnt'+r',combine' cnt rs cnt' rs',cnt*cnt')
Nothing -> compileError ("Missing value for label" <+> pp lbl $$
"among" <+> hsep (punctuate (pp ',') (map fst as)))
param2int (VApp _ q vs) ty = do
(r , ctxt,cnt ) <- getIdxCnt q
(r',rs', cnt') <- compute ctxt vs
return (r+r',rs',cnt)
where
compute [] [] = return (0,[],1)
compute ((_,_,ty):ctxt) (v:vs) = do
(r, rs ,cnt ) <- param2int v ty
(r',rs',cnt') <- compute ctxt vs
return (r*cnt'+r',combine' cnt rs cnt' rs',cnt*cnt')
param2int (VInt n) ty
| Just max <- isTypeInts ty= return (fromIntegral n,[],fromIntegral max+1)
param2int (VMeta i _) ty = do
st <- getMeta i
case st of
Narrowing c ty -> do count <- getCnt ty
return (0,[(1,i-1)],count)
Bound _ v -> param2int v ty
param2int (VSusp i k vs) ty = do
st <- getMeta i
v <- case st of
Narrowing c ty -> do v <- chooseMetaValue c ty
setMeta i (Bound undefined v)
return v
Bound _ v -> return v
g <- globals
param2int (apply g (k v) vs) ty
param2int (VFV c vs) ty = do
v <- variants c (unvariants vs)
param2int v ty
param2int v ty = compileError ("the parameter:" <+> ppValue Unqualified 0 v $$
"cannot be evaluated at compile time.")
combine' 1 rs 1 rs' = []
combine' 1 rs cnt' rs' = rs'
combine' cnt rs 1 rs' = rs
combine' cnt rs cnt' rs' = combine cnt' rs rs'
combine cnt' [] rs' = rs'
combine cnt' rs [] = [(r*cnt',pv) | (r,pv) <- rs]
combine cnt' ((r,pv):rs) ((r',pv'):rs') =
case compare pv pv' of
LT -> (r*cnt', pv ) : combine cnt' rs ((r',pv'):rs')
EQ -> (r*cnt'+r',pv ) : combine cnt' rs ((r',pv'):rs')
GT -> ( r',pv') : combine cnt' ((r,pv):rs) rs'
type ChoiceMap = Map.Map Choice Int
type MetaVars = Map.Map Int MetaState
newtype GenM a = GenM {unGen :: forall r . Globals -> (a -> ChoiceMap -> MetaVars -> r -> Check r) -> ChoiceMap -> MetaVars -> r -> Check r}
instance Functor GenM where
fmap f (GenM m) = GenM (\g k -> m g (k . f))
instance Applicative GenM where
pure x = GenM (\g k -> k x)
(GenM f) <*> (GenM h) = GenM (\g k -> f g (\fn -> h g (\x -> k (fn x))))
instance Alternative GenM where
empty = GenM (\g k svs ms r -> pure r)
(GenM f) <|> (GenM h) = GenM (\g k svs ms r -> f g k svs ms r >>= h g k svs ms)
instance Monad GenM where
(GenM f) >>= h = GenM (\g k -> f g (\x -> case h x of {GenM h -> h g k}))
instance MonadFail GenM where
fail msg = GenM (\_ _ _ _ _ -> fail msg)
runGenM g ms r (GenM f) = f g (\x svs ms xs -> pure (x:xs)) Map.empty ms r
compileError d = GenM (\_ _ _ _ _ -> checkError d)
globals = GenM $ \g k -> k g
variants :: Choice -> [a] -> GenM a
variants c xs = GenM (\g k svs ms r ->
case Map.lookup c svs of
Just j -> k (xs !! j) svs ms r
Nothing -> foldM (\r (j,x) -> k x (Map.insert c j svs) ms r) r (zip [0..] xs))
newMeta c ty = GenM $ \_ k svs ms ->
let i = Map.size ms + 1
in k i svs (Map.insert i (Narrowing c ty) ms)
getMeta i = GenM $ \_ k svs ms r ->
case Map.lookup i ms of
Just v -> k v svs ms r
Nothing -> checkError (pp "Meta variable" <+> ppMeta i <+> "is not defined")
setMeta i st = GenM $ \_ k svs ms ->
k () svs (Map.insert i st ms)
getCnt ty = GenM $ \(Gl gr _) k svs ms r ->
case allParamValues gr ty of
Ok ts -> k (length ts) svs ms r
Bad msg -> checkError (pp msg)
getIdxCnt q = GenM $ \(Gl gr _) k svs ms r ->
case lookupOrigInfo gr q of
Ok (_,ResValue (L _ ty) idx) ->
let (ctxt,QC p) = typeFormCnc ty
in case lookupOrigInfo gr p of
Ok (_,ResParam _ (Just (_,cnt))) -> k (idx,ctxt,cnt) svs ms r
Bad msg -> checkError (pp msg)
Bad msg -> checkError (pp msg)
chooseMetaValue :: Choice -> Type -> GenM Value
chooseMetaValue s ptyp = GenM $ \g@(Gl gr _) k svs ms r ->
case ptyp of
_ | Just n <- isTypeInts ptyp -> foldM (\r i -> k (VInt i) svs ms r) r [0..n]
QC c -> do (mod,info) <- lookupOrigInfo gr c
case info of
ResParam (Just ps) _ -> mkValue mod k svs ms r 0 (unLoc ps)
_ -> checkError (ppQIdent Qualified c <+> "has no parameter values defined")
Q c -> lookupResDef gr c >>= \ty -> unGen (chooseMetaValue s ty) g k svs ms r
RecType lbls -> unGen (mapAccumM mkField s lbls >>= \(_,lbls) -> return (VR lbls)) g k svs ms r
_ -> checkError ("cannot find parameter values for" <+> ptyp)
where
mkValue mod k svs ms r idx [] = return r
mkValue mod k svs ms r idx ((id,ctxt):ps) = do
let (ms',args) = mkVars ms s ctxt
r <- k (VApp poison (mod,id) args) (Map.insert s idx svs) ms' r
mkValue mod k svs ms r (idx+1) ps
mkVars ms c [] = (ms,[])
mkVars ms c ((_,_,ty):ctxt) =
let i = Map.size ms + 1
(c1,c2) = split c
(ms',args) = mkVars (Map.insert i (Narrowing c1 ty) ms) c2 ctxt
in (ms',VMeta i []:args)
mkField c (l,ty) = do
let (c1,c2) = split c
v <- chooseMetaValue c1 ty
return (c2,(l,v))
order :: Ord a => [(a,b)] -> [(a,b)]
order = sortBy (\(r1,_) (r2,_) -> compare r2 r1)
mapAccumM f a [] = return (a,[])
mapAccumM f a (x:xs) = do (a, y) <- f a x
(a,ys) <- mapAccumM f a xs
return (a,y:ys)