summaryrefslogtreecommitdiff
path: root/src-3.0/PGF.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src-3.0/PGF.hs')
-rw-r--r--src-3.0/PGF.hs181
1 files changed, 181 insertions, 0 deletions
diff --git a/src-3.0/PGF.hs b/src-3.0/PGF.hs
new file mode 100644
index 000000000..4a44ac586
--- /dev/null
+++ b/src-3.0/PGF.hs
@@ -0,0 +1,181 @@
+----------------------------------------------------------------------
+-- |
+-- Module : GFCCAPI
+-- Maintainer : Aarne Ranta
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date:
+-- > CVS $Author:
+-- > CVS $Revision:
+--
+-- Reduced Application Programmer's Interface to GF, meant for
+-- embedded GF systems. AR 19/9/2007
+-----------------------------------------------------------------------------
+
+module PGF where
+
+import PGF.CId
+import PGF.Linearize
+import PGF.Generate
+import PGF.Macros
+import PGF.Data
+import PGF.Raw.Convert
+import PGF.Raw.Parse
+import PGF.Parsing.FCFG
+
+import GF.Data.ErrM
+
+import Data.Char
+import qualified Data.Map as Map
+import Control.Monad
+import System.Random (newStdGen)
+import System.Directory (doesFileExist)
+import qualified Text.PrettyPrint as PP
+import qualified Text.ParserCombinators.ReadP as RP
+
+
+-- This API is meant to be used when embedding GF grammars in Haskell
+-- programs. The embedded system is supposed to use the
+-- .gfcc grammar format, which is first produced by the gf program.
+
+---------------------------------------------------
+-- Interface
+---------------------------------------------------
+
+data MultiGrammar = MultiGrammar {gfcc :: GFCC}
+type Language = String
+type Category = String
+type Tree = Exp
+
+file2grammar :: FilePath -> IO MultiGrammar
+
+linearize :: MultiGrammar -> Language -> Tree -> String
+parse :: MultiGrammar -> Language -> Category -> String -> [Tree]
+
+linearizeAll :: MultiGrammar -> Tree -> [String]
+linearizeAllLang :: MultiGrammar -> Tree -> [(Language,String)]
+
+parseAll :: MultiGrammar -> Category -> String -> [[Tree]]
+parseAllLang :: MultiGrammar -> Category -> String -> [(Language,[Tree])]
+
+generateAll :: MultiGrammar -> Category -> [Tree]
+generateRandom :: MultiGrammar -> Category -> IO [Tree]
+generateAllDepth :: MultiGrammar -> Category -> Maybe Int -> [Tree]
+
+readTree :: String -> Tree
+showTree :: Tree -> String
+
+languages :: MultiGrammar -> [Language]
+categories :: MultiGrammar -> [Category]
+
+startCat :: MultiGrammar -> Category
+
+---------------------------------------------------
+-- Implementation
+---------------------------------------------------
+
+file2grammar f = do
+ gfcc <- file2gfcc f
+ return (MultiGrammar gfcc)
+
+file2gfcc f = do
+ s <- readFileIf f
+ g <- parseGrammar s
+ return $ toGFCC g
+
+linearize mgr lang = PGF.Linearize.linearize (gfcc mgr) (mkCId lang)
+
+parse mgr lang cat s =
+ case lookParser (gfcc mgr) (mkCId lang) of
+ Nothing -> error "no parser"
+ Just pinfo -> case parseFCF "bottomup" pinfo (mkCId cat) (words s) of
+ Ok x -> x
+ Bad s -> error s
+
+linearizeAll mgr = map snd . linearizeAllLang mgr
+linearizeAllLang mgr t =
+ [(lang,PGF.linearize mgr lang t) | lang <- languages mgr]
+
+parseAll mgr cat = map snd . parseAllLang mgr cat
+
+parseAllLang mgr cat s =
+ [(lang,ts) | lang <- languages mgr, let ts = parse mgr lang cat s, not (null ts)]
+
+generateRandom mgr cat = do
+ gen <- newStdGen
+ return $ genRandom gen (gfcc mgr) (mkCId cat)
+
+generateAll mgr cat = generate (gfcc mgr) (mkCId cat) Nothing
+generateAllDepth mgr cat = generate (gfcc mgr) (mkCId cat)
+
+readTree s = case RP.readP_to_S (pExp 0) s of
+ [(x,"")] -> x
+ _ -> error "no parse"
+
+pExps :: RP.ReadP [Exp]
+pExps = liftM2 (:) (pExp 1) pExps RP.<++ (RP.skipSpaces >> return [])
+
+pExp :: Int -> RP.ReadP Exp
+pExp n = RP.skipSpaces >> (pParen RP.<++ pApp RP.<++ pNum RP.<++ pStr RP.<++ pMeta)
+ where
+ pParen = RP.between (RP.char '(') (RP.char ')') (pExp 0)
+ pApp = do xs <- RP.option [] (RP.between (RP.char '\\') (RP.string "->") (RP.sepBy1 pIdent (RP.char ',')))
+ f <- pIdent
+ ts <- (if n == 0 then pExps else return [])
+ return (DTr xs (AC f) ts)
+ pStr = RP.char '"' >> liftM (\s -> DTr [] (AS s) []) (RP.manyTill (pEsc RP.<++ RP.get) (RP.char '"'))
+ pEsc = RP.char '\\' >> RP.get
+ pNum = do x <- RP.munch1 isDigit
+ ((RP.char '.' >> RP.munch1 isDigit >>= \y -> return (DTr [] (AF (read (x++"."++y))) []))
+ RP.<++
+ (return (DTr [] (AI (read x)) [])))
+ pMeta = do RP.char '?'
+ x <- RP.munch1 isDigit
+ return (DTr [] (AM (read x)) [])
+
+ pIdent = fmap mkCId (liftM2 (:) (RP.satisfy isIdentFirst) (RP.munch isIdentRest))
+ isIdentFirst c = c == '_' || isLetter c
+ isIdentRest c = c == '_' || c == '\'' || isAlphaNum c
+
+
+showTree = PP.render . ppExp False
+
+ppExp isNested (DTr [] at []) = ppAtom at
+ppExp isNested (DTr xs at ts) = ppParens isNested (ppLambdas xs PP.<+> ppAtom at PP.<+> PP.hsep (map (ppExp True) ts))
+ where
+ ppLambdas [] = PP.empty
+ ppLambdas xs = PP.char '\\' PP.<>
+ PP.hsep (PP.punctuate PP.comma (map (PP.text . prCId) xs)) PP.<+>
+ PP.text "->"
+
+ ppParens True = PP.parens
+ ppParens False = id
+
+ppAtom (AC id) = PP.text (prCId id)
+ppAtom (AS s) = PP.text (show s)
+ppAtom (AI n) = PP.integer n
+ppAtom (AF d) = PP.double d
+ppAtom (AM n) = PP.char '?' PP.<> PP.integer n
+ppAtom (AV id) = PP.text (prCId id)
+
+abstractName mgr = prCId (absname (gfcc mgr))
+
+languages mgr = [prCId l | l <- cncnames (gfcc mgr)]
+
+categories mgr = [prCId c | c <- Map.keys (cats (abstract (gfcc mgr)))]
+
+startCat mgr = lookStartCat (gfcc mgr)
+
+emptyMultiGrammar = MultiGrammar emptyGFCC
+
+------------ for internal use only
+
+err f g ex = case ex of
+ Ok x -> g x
+ Bad s -> f s
+
+readFileIf f = do
+ b <- doesFileExist f
+ if b then readFile f
+ else putStrLn ("file " ++ f ++ " not found") >> return ""