1
0
forked from GitHub/gf-core
Files
gf-core/src/runtime/haskell-bind/PGF2/Internal.hsc
2018-11-27 21:09:35 +01:00

936 lines
41 KiB
Haskell

{-# LANGUAGE ImplicitParams, RankNTypes #-}
module PGF2.Internal(-- * Access the internal structures
FId,isPredefFId,
FunId,Token,Production(..),PArg(..),Symbol(..),Literal(..),
globalFlags, abstrFlags, concrFlags,
concrTotalCats, concrCategories, concrProductions,
concrTotalFuns, concrFunction,
concrTotalSeqs, concrSequence,
-- * Building new PGFs in memory
build, eAbs, eApp, eMeta, eFun, eVar, eTyped, eImplArg, dTyp, hypo,
AbstrInfo, newAbstr, ConcrInfo, newConcr, newPGF,
-- * Expose PGF and Concr for FFI with C
PGF(..), Concr(..),
-- * Write an in-memory PGF to a file
writePGF
) where
#include <pgf/data.h>
import PGF2
import PGF2.FFI
import PGF2.Expr
import PGF2.Type
import System.IO.Unsafe(unsafePerformIO)
import Foreign
import Foreign.C
import Data.IORef
import Data.Maybe(fromMaybe)
import Data.List(sortBy)
import Control.Exception(Exception,throwIO)
import Control.Monad(foldM)
import qualified Data.Map as Map
type Token = String
data Symbol
= SymCat {-# UNPACK #-} !Int {-# UNPACK #-} !LIndex
| SymLit {-# UNPACK #-} !Int {-# UNPACK #-} !LIndex
| SymVar {-# UNPACK #-} !Int {-# UNPACK #-} !Int
| SymKS Token
| SymKP [Symbol] [([Symbol],[String])]
| SymBIND -- the special BIND token
| SymNE -- non exist
| SymSOFT_BIND -- the special SOFT_BIND token
| SymSOFT_SPACE -- the special SOFT_SPACE token
| SymCAPIT -- the special CAPIT token
| SymALL_CAPIT -- the special ALL_CAPIT token
deriving (Eq,Ord,Show)
data Production
= PApply {-# UNPACK #-} !FunId [PArg]
| PCoerce {-# UNPACK #-} !FId
deriving (Eq,Ord,Show)
data PArg = PArg [FId] {-# UNPACK #-} !FId deriving (Eq,Ord,Show)
type FunId = Int
type SeqId = Int
data Literal =
LStr String -- ^ a string constant
| LInt Int -- ^ an integer constant
| LFlt Double -- ^ a floating point constant
deriving (Eq,Ord,Show)
-----------------------------------------------------------------------
-- Access the internal structures
-----------------------------------------------------------------------
globalFlags :: PGF -> [(String,Literal)]
globalFlags p = unsafePerformIO $ do
c_flags <- (#peek PgfPGF, gflags) (pgf p)
flags <- peekFlags c_flags
touchPGF p
return flags
abstrFlags :: PGF -> [(String,Literal)]
abstrFlags p = unsafePerformIO $ do
c_flags <- (#peek PgfPGF, abstract.aflags) (pgf p)
flags <- peekFlags c_flags
touchPGF p
return flags
concrFlags :: Concr -> [(String,Literal)]
concrFlags c = unsafePerformIO $ do
c_flags <- (#peek PgfConcr, cflags) (concr c)
flags <- peekFlags c_flags
touchConcr c
return flags
peekFlags :: Ptr GuSeq -> IO [(String,Literal)]
peekFlags c_flags = do
c_len <- (#peek GuSeq, len) c_flags
peekFlags (c_len :: CInt) (c_flags `plusPtr` (#offset GuSeq, data))
where
peekFlags 0 ptr = return []
peekFlags c_len ptr = do
name <- (#peek PgfFlag, name) ptr >>= peekUtf8CString
value <- (#peek PgfFlag, value) ptr >>= peekLiteral
flags <- peekFlags (c_len-1) (ptr `plusPtr` (#size PgfFlag))
return ((name,value):flags)
peekLiteral :: GuVariant -> IO Literal
peekLiteral p = do
tag <- gu_variant_tag p
ptr <- gu_variant_data p
case tag of
(#const PGF_LITERAL_STR) -> do { val <- peekUtf8CString (ptr `plusPtr` (#offset PgfLiteralStr, val));
return (LStr val) }
(#const PGF_LITERAL_INT) -> do { val <- peek (ptr `plusPtr` (#offset PgfLiteralInt, val));
return (LInt (fromIntegral (val :: CInt))) }
(#const PGF_LITERAL_FLT) -> do { val <- peek (ptr `plusPtr` (#offset PgfLiteralFlt, val));
return (LFlt (realToFrac (val :: CDouble))) }
_ -> error "Unknown literal type in the grammar"
concrTotalCats :: Concr -> FId
concrTotalCats c = unsafePerformIO $ do
c_total_cats <- (#peek PgfConcr, total_cats) (concr c)
touchConcr c
return (fromIntegral (c_total_cats :: CInt))
concrCategories :: Concr -> [(Cat,FId,FId,[String])]
concrCategories c =
unsafePerformIO $
withGuPool $ \tmpPl ->
allocaBytes (#size GuMapItor) $ \itor -> do
exn <- gu_new_exn tmpPl
ref <- newIORef []
fptr <- wrapMapItorCallback (getCategories ref)
(#poke GuMapItor, fn) itor fptr
c_cnccats <- (#peek PgfConcr, cnccats) (concr c)
gu_map_iter c_cnccats itor exn
touchConcr c
freeHaskellFunPtr fptr
cs <- readIORef ref
return (reverse cs)
where
getCategories ref itor key value exn = do
names <- readIORef ref
name <- peekUtf8CString (castPtr key)
c_cnccat <- peek (castPtr value)
c_cats <- (#peek PgfCncCat, cats) c_cnccat
c_len <- (#peek GuSeq, len) c_cats
first <- peek (c_cats `plusPtr` (#offset GuSeq, data)) >>= peekFId
last <- peek (c_cats `plusPtr` ((#offset GuSeq, data) + (fromIntegral (c_len-1::CSizeT))*(#size PgfCCat*))) >>= peekFId
c_n_lins <- (#peek PgfCncCat, n_lins) c_cnccat
arr <- peekArray (fromIntegral (c_n_lins :: CSizeT)) (c_cnccat `plusPtr` (#offset PgfCncCat, labels))
labels <- mapM peekUtf8CString arr
writeIORef ref ((name,first,last,labels) : names)
concrProductions :: Concr -> FId -> [Production]
concrProductions c fid = unsafePerformIO $ do
c_ccats <- (#peek PgfConcr, ccats) (concr c)
res <- alloca $ \pfid -> do
poke pfid (fromIntegral fid :: CInt)
gu_map_find_default c_ccats pfid >>= peek
if res == nullPtr
then do touchConcr c
return []
else do c_prods <- (#peek PgfCCat, prods) res
if c_prods == nullPtr
then do touchConcr c
return []
else do res <- peekSequence (deRef peekProduction) (#size GuVariant) c_prods
touchConcr c
return res
where
peekProduction p = do
tag <- gu_variant_tag p
dt <- gu_variant_data p
case tag of
(#const PGF_PRODUCTION_APPLY) -> do { c_cncfun <- (#peek PgfProductionApply, fun) dt ;
c_funid <- (#peek PgfCncFun, funid) c_cncfun ;
c_args <- (#peek PgfProductionApply, args) dt ;
pargs <- peekSequence peekPArg (#size PgfPArg) c_args ;
return (PApply (fromIntegral (c_funid :: CInt)) pargs) }
(#const PGF_PRODUCTION_COERCE)-> do { c_coerce <- (#peek PgfProductionCoerce, coerce) dt ;
fid <- peekFId c_coerce ;
return (PCoerce fid) }
_ -> error "Unknown production type in the grammar"
where
peekPArg ptr = do
c_hypos <- (#peek PgfPArg, hypos) ptr
hypos <- peekSequence (deRef peekFId) (#size int) c_hypos
c_ccat <- (#peek PgfPArg, ccat) ptr
fid <- peekFId c_ccat
return (PArg hypos fid)
peekFId c_ccat = do
c_fid <- (#peek PgfCCat, fid) c_ccat
return (fromIntegral (c_fid :: CInt))
concrTotalFuns :: Concr -> FunId
concrTotalFuns c = unsafePerformIO $ do
c_cncfuns <- (#peek PgfConcr, cncfuns) (concr c)
c_len <- (#peek GuSeq, len) c_cncfuns
touchConcr c
return (fromIntegral (c_len :: CSizeT))
concrFunction :: Concr -> FunId -> (Fun,[SeqId])
concrFunction c funid = unsafePerformIO $ do
c_cncfuns <- (#peek PgfConcr, cncfuns) (concr c)
c_cncfun <- peek (c_cncfuns `plusPtr` ((#offset GuSeq, data)+funid*(#size PgfCncFun*)))
c_absfun <- (#peek PgfCncFun, absfun) c_cncfun
c_name <- (#peek PgfAbsFun, name) c_absfun
name <- peekUtf8CString c_name
c_n_lins <- (#peek PgfCncFun, n_lins) c_cncfun
arr <- peekArray (fromIntegral (c_n_lins :: CSizeT)) (c_cncfun `plusPtr` (#offset PgfCncFun, lins))
seqs_seq <- (#peek PgfConcr, sequences) (concr c)
touchConcr c
let seqs = seqs_seq `plusPtr` (#offset GuSeq, data)
return (name, map (toSeqId seqs) arr)
where
toSeqId seqs seq = minusPtr seq seqs `div` (#size PgfSequence)
concrTotalSeqs :: Concr -> SeqId
concrTotalSeqs c = unsafePerformIO $ do
seq <- (#peek PgfConcr, sequences) (concr c)
c_len <- (#peek GuSeq, len) seq
touchConcr c
return (fromIntegral (c_len :: CSizeT))
concrSequence :: Concr -> SeqId -> [Symbol]
concrSequence c seqid = unsafePerformIO $ do
c_sequences <- (#peek PgfConcr, sequences) (concr c)
let c_sequence = c_sequences `plusPtr` ((#offset GuSeq, data)+seqid*(#size PgfSequence))
c_syms <- (#peek PgfSequence, syms) c_sequence
res <- peekSequence (deRef peekSymbol) (#size GuVariant) c_syms
touchConcr c
return res
where
peekSymbol p = do
tag <- gu_variant_tag p
dt <- gu_variant_data p
case tag of
(#const PGF_SYMBOL_CAT) -> peekSymbolIdx SymCat dt
(#const PGF_SYMBOL_LIT) -> peekSymbolIdx SymLit dt
(#const PGF_SYMBOL_VAR) -> peekSymbolIdx SymVar dt
(#const PGF_SYMBOL_KS) -> peekSymbolKS dt
(#const PGF_SYMBOL_KP) -> peekSymbolKP dt
(#const PGF_SYMBOL_BIND) -> return SymBIND
(#const PGF_SYMBOL_SOFT_BIND) -> return SymSOFT_BIND
(#const PGF_SYMBOL_NE) -> return SymNE
(#const PGF_SYMBOL_SOFT_SPACE) -> return SymSOFT_SPACE
(#const PGF_SYMBOL_CAPIT) -> return SymCAPIT
(#const PGF_SYMBOL_ALL_CAPIT) -> return SymALL_CAPIT
_ -> error "Unknown symbol type in the grammar"
peekSymbolIdx constr dt = do
c_d <- (#peek PgfSymbolIdx, d) dt
c_r <- (#peek PgfSymbolIdx, r) dt
return (constr (fromIntegral (c_d :: CInt)) (fromIntegral (c_r :: CInt)))
peekSymbolKS dt = do
token <- peekUtf8CString (dt `plusPtr` (#offset PgfSymbolKS, token))
return (SymKS token)
peekSymbolKP dt = do
c_default_form <- (#peek PgfSymbolKP, default_form) dt
default_form <- peekSequence (deRef peekSymbol) (#size GuVariant) c_default_form
c_n_forms <- (#peek PgfSymbolKP, n_forms) dt
forms <- peekForms (c_n_forms :: CSizeT) (dt `plusPtr` (#offset PgfSymbolKP, forms))
return (SymKP default_form forms)
peekForms 0 ptr = return []
peekForms len ptr = do
c_form <- (#peek PgfAlternative, form) ptr
form <- peekSequence (deRef peekSymbol) (#size GuVariant) c_form
c_prefixes <- (#peek PgfAlternative, prefixes) ptr
prefixes <- peekSequence (deRef peekUtf8CString) (#size GuString*) c_prefixes
forms <- peekForms (len-1) (ptr `plusPtr` (#size PgfAlternative))
return ((form,prefixes):forms)
deRef peekValue ptr = peek ptr >>= peekValue
fidString, fidInt, fidFloat, fidVar, fidStart :: FId
fidString = (-1)
fidInt = (-2)
fidFloat = (-3)
fidVar = (-4)
fidStart = (-5)
isPredefFId :: FId -> Bool
isPredefFId = (`elem` [fidString, fidInt, fidFloat, fidVar])
-----------------------------------------------------------------------
-- Building new PGFs in memory
-----------------------------------------------------------------------
data Builder s = Builder (Ptr GuPool) Touch
newtype B s a = B a
build :: (forall s . (?builder :: Builder s) => B s a) -> a
build f =
unsafePerformIO $ do
pool <- gu_new_pool
poolFPtr <- newForeignPtr gu_pool_finalizer pool
let ?builder = Builder pool (touchForeignPtr poolFPtr)
let B res = f
return res
eAbs :: (?builder :: Builder s) => BindType -> String -> B s Expr -> B s Expr
eAbs bind_type var (B (Expr body _)) =
unsafePerformIO $
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_EXPR_ABS)
(#size PgfExprAbs)
(#const gu_alignof(PgfExprAbs))
pptr pool
cvar <- newUtf8CString var pool
(#poke PgfExprAbs, bind_type) ptr (cbind_type :: PgfBindType)
(#poke PgfExprAbs, id) ptr cvar
(#poke PgfExprAbs, body) ptr body
e <- peek pptr
return (B (Expr e touch))
where
(Builder pool touch) = ?builder
cbind_type =
case bind_type of
Explicit -> (#const PGF_BIND_TYPE_EXPLICIT)
Implicit -> (#const PGF_BIND_TYPE_IMPLICIT)
eApp :: (?builder :: Builder s) => B s Expr -> B s Expr -> B s Expr
eApp (B (Expr fun _)) (B (Expr arg _)) =
unsafePerformIO $
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_EXPR_APP)
(#size PgfExprApp)
(#const gu_alignof(PgfExprApp))
pptr pool
(#poke PgfExprApp, fun) ptr fun
(#poke PgfExprApp, arg) ptr arg
e <- peek pptr
return (B (Expr e touch))
where
(Builder pool touch) = ?builder
eMeta :: (?builder :: Builder s) => Int -> B s Expr
eMeta id =
unsafePerformIO $
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_EXPR_META)
(fromIntegral (#size PgfExprMeta))
(#const gu_alignof(PgfExprMeta))
pptr pool
(#poke PgfExprMeta, id) ptr (fromIntegral id :: CInt)
e <- peek pptr
return (B (Expr e touch))
where
(Builder pool touch) = ?builder
eFun :: (?builder :: Builder s) => Fun -> B s Expr
eFun fun =
unsafePerformIO $
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_EXPR_FUN)
(fromIntegral ((#size PgfExprFun)+utf8Length fun))
(#const gu_flex_alignof(PgfExprFun))
pptr pool
pokeUtf8CString fun (ptr `plusPtr` (#offset PgfExprFun, fun))
e <- peek pptr
return (B (Expr e touch))
where
(Builder pool touch) = ?builder
eVar :: (?builder :: Builder s) => Int -> B s Expr
eVar var =
unsafePerformIO $
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_EXPR_VAR)
(#size PgfExprVar)
(#const gu_alignof(PgfExprVar))
pptr pool
(#poke PgfExprVar, var) ptr (fromIntegral var :: CInt)
e <- peek pptr
return (B (Expr e touch))
where
(Builder pool touch) = ?builder
eTyped :: (?builder :: Builder s) => B s Expr -> B s Type -> B s Expr
eTyped (B (Expr e _)) (B (Type ty _)) =
unsafePerformIO $
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_EXPR_TYPED)
(#size PgfExprTyped)
(#const gu_alignof(PgfExprTyped))
pptr pool
(#poke PgfExprTyped, expr) ptr e
(#poke PgfExprTyped, type) ptr ty
e <- peek pptr
return (B (Expr e touch))
where
(Builder pool touch) = ?builder
eImplArg :: (?builder :: Builder s) => B s Expr -> B s Expr
eImplArg (B (Expr e _)) =
unsafePerformIO $
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_EXPR_IMPL_ARG)
(#size PgfExprImplArg)
(#const gu_alignof(PgfExprImplArg))
pptr pool
(#poke PgfExprImplArg, expr) ptr e
e <- peek pptr
return (B (Expr e touch))
where
(Builder pool touch) = ?builder
hypo :: BindType -> CId -> B s Type -> (B s Hypo)
hypo bind_type var (B ty) = B (bind_type,var,ty)
dTyp :: (?builder :: Builder s) => [B s Hypo] -> Cat -> [B s Expr] -> B s Type
dTyp hypos cat es =
unsafePerformIO $ do
ptr <- gu_malloc_aligned pool
((#size PgfType)+n_exprs*(#size GuVariant))
(#const gu_flex_alignof(PgfType))
c_hypos <- newHypos hypos pool
c_cat <- newUtf8CString cat pool
(#poke PgfType, hypos) ptr c_hypos
(#poke PgfType, cid) ptr c_cat
(#poke PgfType, n_exprs) ptr n_exprs
pokeArray (ptr `plusPtr` (#offset PgfType, exprs)) [e | B (Expr e _) <- es]
return (B (Type ptr touch))
where
(Builder pool touch) = ?builder
n_exprs = fromIntegral (length es) :: CSizeT
newHypos :: [B s Hypo] -> Ptr GuPool -> IO (Ptr GuSeq)
newHypos hypos pool = do
c_hypos <- gu_make_seq (#size PgfHypo) (fromIntegral (length hypos)) pool
pokeHypos (c_hypos `plusPtr` (#offset GuSeq, data)) hypos
return c_hypos
where
pokeHypos ptr [] = return ()
pokeHypos ptr (B (bind_type,var,Type ty _):hypos) = do
c_var <- newUtf8CString var pool
(#poke PgfHypo, bind_type) ptr (cbind_type :: PgfBindType)
(#poke PgfHypo, cid) ptr c_var
(#poke PgfHypo, type) ptr ty
pokeHypos (ptr `plusPtr` (#size PgfHypo)) hypos
where
cbind_type =
case bind_type of
Explicit -> (#const PGF_BIND_TYPE_EXPLICIT)
Implicit -> (#const PGF_BIND_TYPE_IMPLICIT)
data AbstrInfo = AbstrInfo (Ptr GuSeq) (Ptr GuSeq) (Map.Map String (Ptr PgfAbsCat)) (Ptr GuSeq) (Map.Map String (Ptr PgfAbsFun)) (Ptr PgfAbsFun) (Ptr GuBuf) Touch
newAbstr :: (?builder :: Builder s) => [(String,Literal)] ->
[(Cat,[B s Hypo],Float)] ->
[(Fun,B s Type,Int,Float)] ->
AbstrInfo
newAbstr aflags cats funs = unsafePerformIO $ do
c_aflags <- newFlags aflags pool
(c_cats,abscats) <- newAbsCats (sortByFst3 cats) pool
(c_funs,absfuns) <- newAbsFuns (sortByFst4 funs) pool
c_abs_lin_fun <- newAbsLinFun
c_non_lexical_buf <- gu_make_buf (#size PgfProductionIdxEntry) pool
return (AbstrInfo c_aflags c_cats abscats c_funs absfuns c_abs_lin_fun c_non_lexical_buf touch)
where
(Builder pool touch) = ?builder
newAbsCats values pool = do
c_seq <- gu_make_seq (#size PgfAbsCat) (fromIntegral (length values)) pool
abscats <- pokeElems (c_seq `plusPtr` (#offset GuSeq, data)) Map.empty values
return (c_seq,abscats)
where
pokeElems ptr abscats [] = return abscats
pokeElems ptr abscats (x:xs) = do
abscats <- pokeAbsCat ptr abscats x
pokeElems (ptr `plusPtr` (#size PgfAbsCat)) abscats xs
pokeAbsCat ptr abscats (name,hypos,prob) = do
c_name <- newUtf8CString name pool
c_hypos <- newHypos hypos pool
(#poke PgfAbsCat, name) ptr c_name
(#poke PgfAbsCat, context) ptr c_hypos
(#poke PgfAbsCat, prob) ptr (realToFrac prob :: CFloat)
return (Map.insert name ptr abscats)
newAbsFuns values pool = do
c_seq <- gu_make_seq (#size PgfAbsFun) (fromIntegral (length values)) pool
absfuns <- pokeElems (c_seq `plusPtr` (#offset GuSeq, data)) Map.empty values
return (c_seq,absfuns)
where
pokeElems ptr absfuns [] = return absfuns
pokeElems ptr absfuns (x:xs) = do
absfuns <- pokeAbsFun ptr absfuns x
pokeElems (ptr `plusPtr` (#size PgfAbsFun)) absfuns xs
pokeAbsFun ptr absfuns (name,B (Type c_ty _),arity,prob) = do
pfun <- gu_alloc_variant (#const PGF_EXPR_FUN)
(fromIntegral ((#size PgfExprFun)+utf8Length name))
(#const gu_flex_alignof(PgfExprFun))
(ptr `plusPtr` (#offset PgfAbsFun, ep.expr)) pool
let c_name = (pfun `plusPtr` (#offset PgfExprFun, fun))
pokeUtf8CString name c_name
(#poke PgfAbsFun, name) ptr c_name
(#poke PgfAbsFun, type) ptr c_ty
(#poke PgfAbsFun, arity) ptr (fromIntegral arity :: CInt)
(#poke PgfAbsFun, defns) ptr nullPtr
(#poke PgfAbsFun, ep.prob) ptr (realToFrac prob :: CFloat)
return (Map.insert name ptr absfuns)
newAbsLinFun = do
ptr <- gu_malloc_aligned pool
(#size PgfAbsFun)
(#const gu_alignof(PgfAbsFun))
c_wild <- newUtf8CString "_" pool
c_ty <- gu_malloc_aligned pool
(#size PgfType)
(#const gu_alignof(PgfType))
(#poke PgfType, hypos) c_ty nullPtr
(#poke PgfType, cid) c_ty c_wild
(#poke PgfType, n_exprs) c_ty (0 :: CSizeT)
(#poke PgfAbsFun, name) ptr c_wild
(#poke PgfAbsFun, type) ptr c_ty
(#poke PgfAbsFun, arity) ptr (0 :: CSizeT)
(#poke PgfAbsFun, defns) ptr nullPtr
(#poke PgfAbsFun, ep.prob) ptr (- log 0 :: CFloat)
(#poke PgfAbsFun, ep.expr) ptr nullPtr
return ptr
data ConcrInfo = ConcrInfo (Ptr GuSeq) (Ptr GuMap) (Ptr GuMap) (Ptr GuSeq) (Ptr GuSeq) (Ptr GuMap) (Ptr PgfConcr -> Ptr GuPool -> IO ()) CInt
newConcr :: (?builder :: Builder s) => AbstrInfo ->
[(String,Literal)] -> -- ^ Concrete syntax flags
[(String,String)] -> -- ^ Printnames
[(FId,[FunId])] -> -- ^ Lindefs
[(FId,[FunId])] -> -- ^ Linrefs
[(FId,[Production])] -> -- ^ Productions
[(Fun,[SeqId])] -> -- ^ Concrete functions (must be sorted by Fun)
[[Symbol]] -> -- ^ Sequences (must be sorted)
[(Cat,FId,FId,[String])] -> -- ^ Concrete categories
FId -> -- ^ The total count of the categories
ConcrInfo
newConcr (AbstrInfo _ _ abscats _ absfuns c_abs_lin_fun c_non_lexical_buf _) cflags printnames lindefs linrefs prods cncfuns sequences cnccats total_cats = unsafePerformIO $ do
c_cflags <- newFlags cflags pool
c_printname <- newMap (#size GuString) gu_string_hasher newUtf8CString
(#size GuString) (pokeString pool)
printnames pool
c_seqs <- newSequence (#size PgfSequence) pokeSequence sequences pool
let seqs_ptr = c_seqs `plusPtr` (#offset GuSeq, data)
c_cncfuns <- newSequence (#size PgfCncFun*) (pokeCncFun seqs_ptr) (zip [0..] cncfuns) pool
let funs_ptr = c_cncfuns `plusPtr` (#offset GuSeq, data)
c_ccats <- gu_make_map (#size int) gu_int_hasher
(#size PgfCCat*) gu_null_struct
(#const GU_MAP_DEFAULT_INIT_SIZE)
pool
mapM_ (addLindefs c_ccats funs_ptr) lindefs
mapM_ (addLinrefs c_ccats funs_ptr) linrefs
mk_index <- foldM (addProductions c_ccats funs_ptr c_non_lexical_buf) (\concr pool -> return ()) prods
c_cnccats <- newMap (#size GuString) gu_string_hasher newUtf8CString (#size PgfCncCat*) (pokeCncCat c_ccats) (map (\v@(k,_,_,_) -> (k,v)) cnccats) pool
return (ConcrInfo c_cflags c_printname c_ccats c_cncfuns c_seqs c_cnccats mk_index (fromIntegral total_cats))
where
(Builder pool touch) = ?builder
pokeCncFun seqs_ptr ptr cncfun = do
c_cncfun <- newCncFun absfuns nullPtr cncfun pool
poke ptr c_cncfun
pokeSequence c_seq syms = do
c_syms <- newSymbols syms pool
(#poke PgfSequence, syms) c_seq c_syms
(#poke PgfSequence, idx) c_seq nullPtr
addLindefs c_ccats funs_ptr (fid,funids) = do
c_ccat <- getCCat c_ccats fid pool
c_funs <- newSequence (#size PgfCncFun*) (pokeRefDefFunId funs_ptr) funids pool
(#poke PgfCCat, lindefs) c_ccat c_funs
addLinrefs c_ccats funs_ptr (fid,funids) = do
c_ccat <- getCCat c_ccats fid pool
c_funs <- newSequence (#size PgfCncFun*) (pokeRefDefFunId funs_ptr) funids pool
(#poke PgfCCat, linrefs) c_ccat c_funs
addProductions c_ccats funs_ptr c_non_lexical_buf mk_index (fid,prods) = do
c_ccat <- getCCat c_ccats fid pool
let n_prods = length prods
c_prods <- gu_make_seq (#size PgfProduction) (fromIntegral n_prods) pool
(#poke PgfCCat, prods) c_ccat c_prods
pokeProductions c_ccat (c_prods `plusPtr` (#offset GuSeq, data)) 0 (n_prods-1) mk_index prods
where
pokeProductions c_ccat ptr top bot mk_index [] = return mk_index
pokeProductions c_ccat ptr top bot mk_index (prod:prods) = do
(is_lexical,c_prod) <- newProduction c_ccats funs_ptr c_non_lexical_buf prod pool
let mk_index' = \concr pool -> do pgf_parser_index concr c_ccat c_prod is_lexical pool
pgf_lzr_index concr c_ccat c_prod is_lexical pool
mk_index concr pool
if is_lexical == 0
then do poke (ptr `plusPtr` ((#size PgfProduction)*top)) c_prod
pokeProductions c_ccat ptr (top+1) bot mk_index' prods
else do poke (ptr `plusPtr` ((#size PgfProduction)*bot)) c_prod
pokeProductions c_ccat ptr top (bot-1) mk_index' prods
pokeRefDefFunId funs_ptr ptr funid = do
let c_fun = funs_ptr `plusPtr` (funid * (#size PgfCncFun))
(#poke PgfCncFun, absfun) c_fun c_abs_lin_fun
poke ptr c_fun
pokeCncCat c_ccats ptr (name,start,end,labels) = do
let n_lins = fromIntegral (length labels) :: CSizeT
c_cnccat <- gu_malloc_aligned pool
((#size PgfCncCat)+n_lins*(#size GuString))
(#const gu_flex_alignof(PgfCncCat))
case Map.lookup name abscats of
Just c_abscat -> (#poke PgfCncCat, abscat) c_cnccat c_abscat
Nothing -> throwIO (PGFError ("The category "++name++" is not in the abstract syntax"))
c_ccats <- newSequence (#size PgfCCat*) pokeFId [start..end] pool
(#poke PgfCncCat, cats) c_cnccat c_ccats
pokeLabels (c_cnccat `plusPtr` (#offset PgfCncCat, labels)) labels
poke ptr c_cnccat
where
pokeFId ptr fid = do
c_ccat <- getCCat c_ccats fid pool
poke ptr c_ccat
pokeLabels ptr [] = return []
pokeLabels ptr (l:ls) = do
c_l <- newUtf8CString l pool
poke ptr c_l
pokeLabels (ptr `plusPtr` (#size GuString)) ls
newPGF :: (?builder :: Builder s) => [(String,Literal)] ->
AbsName ->
AbstrInfo ->
[(ConcName,ConcrInfo)] ->
B s PGF
newPGF gflags absname (AbstrInfo c_aflags c_cats _ c_funs _ c_abs_lin_fun _ _) concrs =
unsafePerformIO $ do
ptr <- gu_malloc_aligned pool
(#size PgfPGF)
(#const gu_alignof(PgfPGF))
c_gflags <- newFlags gflags pool
c_absname <- newUtf8CString absname pool
let c_abstr = ptr `plusPtr` (#offset PgfPGF, abstract)
c_concrs <- newSequence (#size PgfConcr) (pokeConcr c_abstr) concrs pool
(#poke PgfPGF, major_version) ptr (2 :: (#type uint16_t))
(#poke PgfPGF, minor_version) ptr (0 :: (#type uint16_t))
(#poke PgfPGF, gflags) ptr c_gflags
(#poke PgfPGF, abstract.name) ptr c_absname
(#poke PgfPGF, abstract.aflags) ptr c_aflags
(#poke PgfPGF, abstract.funs) ptr c_funs
(#poke PgfPGF, abstract.cats) ptr c_cats
(#poke PgfPGF, abstract.abs_lin_fun) ptr c_abs_lin_fun
(#poke PgfPGF, concretes) ptr c_concrs
(#poke PgfPGF, pool) ptr pool
return (B (PGF ptr touch))
where
(Builder pool touch) = ?builder
pokeConcr c_abstr ptr (name, ConcrInfo c_cflags c_printnames c_ccats c_cncfuns c_seqs c_cnccats mk_index c_total_cats) = do
c_name <- newUtf8CString name pool
c_fun_indices <- gu_make_map (#size GuString) gu_string_hasher
(#size PgfCncOverloadMap*) gu_null_struct
(#const GU_MAP_DEFAULT_INIT_SIZE)
pool
c_coerce_idx <- gu_make_map (#size PgfCCat*) gu_addr_hasher
(#size GuBuf*) gu_null_struct
(#const GU_MAP_DEFAULT_INIT_SIZE)
pool
(#poke PgfConcr, name) ptr c_name
(#poke PgfConcr, abstr) ptr c_abstr
(#poke PgfConcr, cflags) ptr c_cflags
(#poke PgfConcr, printnames) ptr c_printnames
(#poke PgfConcr, ccats) ptr c_ccats
(#poke PgfConcr, fun_indices) ptr c_fun_indices
(#poke PgfConcr, coerce_idx) ptr c_coerce_idx
(#poke PgfConcr, cncfuns) ptr c_cncfuns
(#poke PgfConcr, sequences) ptr c_seqs
(#poke PgfConcr, cnccats) ptr c_cnccats
(#poke PgfConcr, total_cats) ptr c_total_cats
(#poke PgfConcr, pool) ptr nullPtr
mk_index ptr pool
newFlags :: [(String,Literal)] -> Ptr GuPool -> IO (Ptr GuSeq)
newFlags flags pool = newSequence (#size PgfFlag) pokeFlag (sortByFst flags) pool
where
pokeFlag c_flag (name,value) = do
c_name <- newUtf8CString name pool
c_value <- newLiteral value pool
(#poke PgfFlag, name) c_flag c_name
(#poke PgfFlag, value) c_flag c_value
newLiteral :: Literal -> Ptr GuPool -> IO GuVariant
newLiteral (LStr val) pool =
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_LITERAL_STR)
(fromIntegral ((#size PgfLiteralStr)+utf8Length val))
(#const gu_flex_alignof(PgfLiteralStr))
pptr pool
pokeUtf8CString val (ptr `plusPtr` (#offset PgfLiteralStr, val))
peek pptr
newLiteral (LInt val) pool =
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_LITERAL_INT)
(fromIntegral (#size PgfLiteralInt))
(#const gu_alignof(PgfLiteralInt))
pptr pool
(#poke PgfLiteralInt, val) ptr (fromIntegral val :: CInt)
peek pptr
newLiteral (LFlt val) pool =
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_LITERAL_FLT)
(fromIntegral (#size PgfLiteralFlt))
(#const gu_alignof(PgfLiteralFlt))
pptr pool
(#poke PgfLiteralFlt, val) ptr (realToFrac val :: CDouble)
peek pptr
newProduction :: Ptr GuMap -> Ptr PgfCncFun -> Ptr GuBuf -> Production -> Ptr GuPool -> IO ((#type bool), GuVariant)
newProduction c_ccats funs_ptr c_non_lexical_buf (PApply fun_id args) pool =
alloca $ \pptr -> do
let c_fun = funs_ptr `plusPtr` (fun_id * (#size PgfCncFun))
c_args <- newSequence (#size PgfPArg) pokePArg args pool
ptr <- gu_alloc_variant (#const PGF_PRODUCTION_APPLY)
(fromIntegral (#size PgfProductionApply))
(#const gu_alignof(PgfProductionApply))
pptr pool
(#poke PgfProductionApply, fun) ptr c_fun
(#poke PgfProductionApply, args) ptr c_args
is_lexical <- pgf_production_is_lexical ptr c_non_lexical_buf pool
c_prod <- peek pptr
return (is_lexical,c_prod)
where
pokePArg ptr (PArg hypos ccat) = do
c_ccat <- getCCat c_ccats ccat pool
(#poke PgfPArg, ccat) ptr c_ccat
c_hypos <- newSequence (#size PgfCCat*) pokeCCat hypos pool
(#poke PgfPArg, hypos) ptr c_hypos
pokeCCat ptr ccat = do
c_ccat <- getCCat c_ccats ccat pool
poke ptr c_ccat
newProduction c_ccats funs_ptr c_non_lexical_buf (PCoerce fid) pool =
alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_PRODUCTION_COERCE)
(fromIntegral (#size PgfProductionCoerce))
(#const gu_alignof(PgfProductionCoerce))
pptr pool
c_ccat <- getCCat c_ccats fid pool
(#poke PgfProductionCoerce, coerce) ptr c_ccat
c_prod <- peek pptr
return (0,c_prod)
newCncFun absfuns seqs_ptr (funid,(fun,seqids)) pool =
do let c_absfun = fromMaybe nullPtr (Map.lookup fun absfuns)
c_ep = if c_absfun == nullPtr
then nullPtr
else c_absfun `plusPtr` (#offset PgfAbsFun, ep)
n_lins = fromIntegral (length seqids) :: CSizeT
ptr <- gu_malloc_aligned pool
((#size PgfCncFun)+n_lins*(#size PgfSequence*))
(#const gu_flex_alignof(PgfCncFun))
(#poke PgfCncFun, absfun) ptr c_absfun
(#poke PgfCncFun, ep) ptr c_ep
(#poke PgfCncFun, funid) ptr (funid :: CInt)
(#poke PgfCncFun, n_lins) ptr n_lins
pokeSequences seqs_ptr (ptr `plusPtr` (#offset PgfCncFun, lins)) seqids
return ptr
where
pokeSequences seqs_ptr ptr [] = return ()
pokeSequences seqs_ptr ptr (seqid:seqids) = do
poke ptr (seqs_ptr `plusPtr` (seqid * (#size PgfSequence)))
pokeSequences seqs_ptr (ptr `plusPtr` (#size PgfSequence*)) seqids
getCCat c_ccats fid pool =
alloca $ \pfid -> do
poke pfid (fromIntegral fid :: CInt)
ptr <- gu_map_find_default c_ccats pfid
c_ccat <- peek ptr
if c_ccat /= nullPtr
then return c_ccat
else do c_ccat <- gu_malloc_aligned pool
(#size PgfCCat)
(#const gu_alignof(PgfCCat))
(#poke PgfCCat, cnccat) c_ccat nullPtr
(#poke PgfCCat, lindefs) c_ccat nullPtr
(#poke PgfCCat, linrefs) c_ccat nullPtr
(#poke PgfCCat, n_synprods) c_ccat (0 :: CSizeT)
(#poke PgfCCat, prods) c_ccat nullPtr
(#poke PgfCCat, viterbi_prob) c_ccat (0 :: CFloat)
(#poke PgfCCat, fid) c_ccat fid
(#poke PgfCCat, conts) c_ccat nullPtr
(#poke PgfCCat, answers) c_ccat nullPtr
ptr <- gu_map_insert c_ccats pfid
poke ptr c_ccat
return c_ccat
newSymbol :: Symbol -> Ptr GuPool -> IO GuVariant
newSymbol (SymCat d r) pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_CAT)
(fromIntegral (#size PgfSymbolCat))
(#const gu_alignof(PgfSymbolCat))
pptr pool
(#poke PgfSymbolCat, d) ptr (fromIntegral d :: CInt)
(#poke PgfSymbolCat, r) ptr (fromIntegral r :: CInt)
peek pptr
newSymbol (SymLit d r) pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_LIT)
(fromIntegral (#size PgfSymbolLit))
(#const gu_alignof(PgfSymbolLit))
pptr pool
(#poke PgfSymbolLit, d) ptr (fromIntegral d :: CInt)
(#poke PgfSymbolLit, r) ptr (fromIntegral r :: CInt)
peek pptr
newSymbol (SymVar d r) pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_VAR)
(fromIntegral (#size PgfSymbolVar))
(#const gu_alignof(PgfSymbolVar))
pptr pool
(#poke PgfSymbolVar, d) ptr (fromIntegral d :: CInt)
(#poke PgfSymbolVar, r) ptr (fromIntegral r :: CInt)
peek pptr
newSymbol (SymKS t) pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_KS)
(fromIntegral ((#size PgfSymbolKS)+utf8Length t))
(#const gu_flex_alignof(PgfSymbolKS))
pptr pool
pokeUtf8CString t (ptr `plusPtr` (#offset PgfSymbolKS, token))
peek pptr
newSymbol (SymKP def alts) pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_KP)
(fromIntegral ((#size PgfSymbolKP)+(length alts * (#size PgfAlternative))))
(#const gu_flex_alignof(PgfSymbolKP))
pptr pool
c_def <- newSymbols def pool
(#poke PgfSymbolKP, default_form) ptr c_def
pokeAlternatives (ptr `plusPtr` (#offset PgfSymbolKP, forms)) alts pool
peek pptr
newSymbol SymBIND pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_BIND)
(fromIntegral (#size PgfSymbolBIND))
(#const gu_alignof(PgfSymbolBIND))
pptr pool
peek pptr
newSymbol SymNE pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_NE)
(fromIntegral (#size PgfSymbolNE))
(#const gu_alignof(PgfSymbolNE))
pptr pool
peek pptr
newSymbol SymSOFT_BIND pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_SOFT_BIND)
(fromIntegral (#size PgfSymbolBIND))
(#const gu_alignof(PgfSymbolBIND))
pptr pool
peek pptr
newSymbol SymSOFT_SPACE pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_SOFT_SPACE)
(fromIntegral (#size PgfSymbolBIND))
(#const gu_alignof(PgfSymbolBIND))
pptr pool
peek pptr
newSymbol SymCAPIT pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_CAPIT)
(fromIntegral (#size PgfSymbolCAPIT))
(#const gu_alignof(PgfSymbolCAPIT))
pptr pool
peek pptr
newSymbol SymALL_CAPIT pool = alloca $ \pptr -> do
ptr <- gu_alloc_variant (#const PGF_SYMBOL_ALL_CAPIT)
(fromIntegral (#size PgfSymbolCAPIT))
(#const gu_alignof(PgfSymbolCAPIT))
pptr pool
peek pptr
newSymbols syms pool = newSequence (#size PgfSymbol) pokeSymbol syms pool
where
pokeSymbol p_sym sym = do
c_sym <- newSymbol sym pool
poke p_sym c_sym
pokeAlternatives ptr [] pool = return ()
pokeAlternatives ptr ((syms,prefixes):alts) pool = do
c_syms <- newSymbols syms pool
c_prefixes <- newSequence (#size GuString) (pokeString pool) prefixes pool
(#poke PgfAlternative, form) ptr c_syms
(#poke PgfAlternative, prefixes) ptr c_prefixes
pokeAlternatives (ptr `plusPtr` (#size PgfAlternative)) alts pool
pokeString pool c_elem str = do
c_str <- newUtf8CString str pool
poke c_elem c_str
newMap key_size hasher newKey elem_size pokeElem values pool = do
map <- gu_make_map key_size hasher
elem_size gu_null_struct
(#const GU_MAP_DEFAULT_INIT_SIZE)
pool
insert map values pool
return map
where
insert map [] pool = return ()
insert map ((key,elem):values) pool = do
c_key <- newKey key pool
c_elem <- gu_map_insert map c_key
pokeElem c_elem elem
insert map values pool
writePGF :: FilePath -> PGF -> IO ()
writePGF fpath p = do
pool <- gu_new_pool
exn <- gu_new_exn pool
withCString fpath $ \c_fpath ->
pgf_write (pgf p) c_fpath exn
touchPGF p
failed <- gu_exn_is_raised exn
if failed
then do is_errno <- gu_exn_caught exn gu_exn_type_GuErrno
if is_errno
then do perrno <- (#peek GuExn, data.data) exn
errno <- peek perrno
gu_pool_free pool
ioError (errnoToIOError "writePGF" (Errno errno) Nothing (Just fpath))
else do gu_pool_free pool
throwIO (PGFError "The grammar cannot be stored")
else do gu_pool_free pool
return ()
sortByFst = sortBy (\(x,_) (y,_) -> compare x y)
sortByFst3 = sortBy (\(x,_,_) (y,_,_) -> compare x y)
sortByFst4 = sortBy (\(x,_,_,_) (y,_,_,_) -> compare x y)