---------------------------------------------------------------------- -- | -- Module : PGFtoProlog -- Maintainer : Peter Ljunglöf -- -- exports a GF grammar into a Prolog module ----------------------------------------------------------------------------- module GF.Compile.PGFtoProlog (grammar2prolog) where import PGF(mkCId,wildCId,showCId) import PGF.Internal --import PGF.Macros import GF.Data.Operations import qualified Data.Array.IArray as Array import qualified Data.Set as Set import qualified Data.Map as Map import qualified Data.IntMap as IntMap import Data.Char (isAlphaNum, isAscii, isAsciiLower, isAsciiUpper, ord) import Data.List (isPrefixOf, mapAccumL) grammar2prolog :: PGF -> String grammar2prolog pgf = ("%% This file was automatically generated by GF" +++++ ":- style_check(-singleton)." +++++ plFacts wildCId "abstract" 1 "(?AbstractName)" [[plp name]] ++++ plFacts wildCId "concrete" 2 "(?AbstractName, ?ConcreteName)" [[plp name, plp cncname] | cncname <- Map.keys (concretes pgf)] ++++ plFacts wildCId "flag" 2 "(?Flag, ?Value): global flags" [[plp f, plp v] | (f, v) <- Map.assocs (gflags pgf)] ++++ plAbstract name (abstract pgf) ++++ unlines (map plConcrete (Map.assocs (concretes pgf))) ) where name = absname pgf ---------------------------------------------------------------------- -- abstract syntax plAbstract :: CId -> Abstr -> String plAbstract name abs = (plHeader "Abstract syntax" ++++ plFacts name "flag" 2 "(?Flag, ?Value): flags for abstract syntax" [[plp f, plp v] | (f, v) <- Map.assocs (aflags abs)] ++++ plFacts name "cat" 2 "(?Type, ?[X:Type,...])" [[plType cat args, plHypos hypos'] | (cat, (hypos,_,_)) <- Map.assocs (cats abs), let ((_, subst), hypos') = mapAccumL alphaConvertHypo emptyEnv hypos, let args = reverse [EFun x | (_,x) <- subst]] ++++ plFacts name "fun" 3 "(?Fun, ?Type, ?[X:Type,...])" [[plp fun, plType cat args, plHypos hypos] | (fun, (typ, _, _, _)) <- Map.assocs (funs abs), let (_, DTyp hypos cat args) = alphaConvert emptyEnv typ] ++++ plFacts name "def" 2 "(?Fun, ?Expr)" [[plp fun, plp expr] | (fun, (_, _, Just (eqs,_), _)) <- Map.assocs (funs abs), let (_, expr) = alphaConvert emptyEnv eqs] ) where plType cat args = plTerm (plp cat) (map plp args) plHypos hypos = plList [plOper ":" (plp x) (plp ty) | (_, x, ty) <- hypos] ---------------------------------------------------------------------- -- concrete syntax plConcrete :: (CId, Concr) -> String plConcrete (name, cnc) = (plHeader ("Concrete syntax: " ++ plp name) ++++ plFacts name "flag" 2 "(?Flag, ?Value): flags for concrete syntax" [[plp f, plp v] | (f, v) <- Map.assocs (cflags cnc)] ++++ plFacts name "printname" 2 "(?AbsFun/AbsCat, ?Atom)" [[plp f, plp n] | (f, n) <- Map.assocs (printnames cnc)] ++++ plFacts name "lindef" 2 "(?CncCat, ?CncFun)" [[plCat cat, plFun fun] | (cat, funs) <- IntMap.assocs (lindefs cnc), fun <- funs] ++++ plFacts name "prod" 3 "(?CncCat, ?CncFun, ?[CncCat])" [[plCat cat, fun, plTerm "c" (map plCat args)] | (cat, set) <- IntMap.toList (productions cnc), (fun, args) <- map plProduction (Set.toList set)] ++++ plFacts name "cncfun" 3 "(?CncFun, ?[Seq,...], ?AbsFun)" [[plFun fun, plTerm "s" (map plSeq (Array.elems lins)), plp absfun] | (fun, CncFun absfun lins) <- Array.assocs (cncfuns cnc)] ++++ plFacts name "seq" 2 "(?Seq, ?[Term])" [[plSeq seq, plp (Array.elems symbols)] | (seq, symbols) <- Array.assocs (sequences cnc)] ++++ plFacts name "cnccat" 2 "(?AbsCat, ?[CnCCat])" [[plp cat, plList (map plCat [start..end])] | (cat, CncCat start end _) <- Map.assocs (cnccats cnc)] ) where plProduction (PCoerce arg) = ("-", [arg]) plProduction (PApply funid args) = (plFun funid, [fid | PArg hypos fid <- args]) ---------------------------------------------------------------------- -- prolog-printing pgf datatypes instance PLPrint Type where plp (DTyp hypos cat args) | null hypos = result | otherwise = plOper " -> " plHypos result where result = plTerm (plp cat) (map plp args) plHypos = plList [plOper ":" (plp x) (plp ty) | (_,x,ty) <- hypos] instance PLPrint Expr where plp (EFun x) = plp x plp (EAbs _ x e)= plOper "^" (plp x) (plp e) plp (EApp e e') = plOper " * " (plp e) (plp e') plp (ELit lit) = plp lit plp (EMeta n) = "Meta_" ++ show n instance PLPrint Patt where plp (PVar x) = plp x plp (PApp f ps) = plOper " * " (plp f) (plp ps) plp (PLit lit) = plp lit instance PLPrint Equation where plp (Equ patterns result) = plOper ":" (plp patterns) (plp result) instance PLPrint CId where plp cid | isLogicalVariable str || cid == wildCId = plVar str | otherwise = plAtom str where str = showCId cid instance PLPrint Literal where plp (LStr s) = plp s plp (LInt n) = plp (show n) plp (LFlt f) = plp (show f) instance PLPrint Symbol where plp (SymCat n l) = plOper ":" (show n) (show l) plp (SymLit n l) = plTerm "lit" [show n, show l] plp (SymVar n l) = plTerm "var" [show n, show l] plp (SymKS t) = plAtom t plp (SymKP ts alts) = plTerm "pre" [plList (map plp ts), plList (map plAlt alts)] where plAlt (ps,ts) = plOper "/" (plList (map plp ps)) (plList (map plAtom ts)) class PLPrint a where plp :: a -> String plps :: [a] -> String plps = plList . map plp instance PLPrint Char where plp c = plAtom [c] plps s = plAtom s instance PLPrint a => PLPrint [a] where plp = plps ---------------------------------------------------------------------- -- other prolog-printing functions plCat :: Int -> String plCat n = plAtom ('c' : show n) plFun :: Int -> String plFun n = plAtom ('f' : show n) plSeq :: Int -> String plSeq n = plAtom ('s' : show n) plHeader :: String -> String plHeader hdr = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n%% " ++ hdr ++ "\n" plFacts :: CId -> String -> Int -> String -> [[String]] -> String plFacts mod pred arity comment facts = "%% " ++ pred ++ comment ++++ clauses where clauses = (if facts == [] then ":- dynamic " ++ pred ++ "/" ++ show arity ++ ".\n" else unlines [mod' ++ plTerm pred args ++ "." | args <- facts]) mod' = if mod == wildCId then "" else plp mod ++ ": " plTerm :: String -> [String] -> String plTerm fun args = plAtom fun ++ prParenth (prTList ", " args) plList :: [String] -> String plList xs = prBracket (prTList "," xs) plOper :: String -> String -> String -> String plOper op a b = prParenth (a ++ op ++ b) plVar :: String -> String plVar = varPrefix . concatMap changeNonAlphaNum where varPrefix var@(c:_) | isAsciiUpper c || c=='_' = var | otherwise = "_" ++ var changeNonAlphaNum c | isAlphaNumUnderscore c = [c] | otherwise = "_" ++ show (ord c) ++ "_" plAtom :: String -> String plAtom "" = "''" plAtom atom@(c:cs) | isAsciiLower c && all isAlphaNumUnderscore cs || c == '\'' && cs /= "" && last cs == '\'' = atom | otherwise = "'" ++ changeQuote atom ++ "'" where changeQuote ('\'':cs) = '\\' : '\'' : changeQuote cs changeQuote ('\\':cs) = '\\' : '\\' : changeQuote cs changeQuote (c:cs) = c : changeQuote cs changeQuote "" = "" isAlphaNumUnderscore :: Char -> Bool isAlphaNumUnderscore c = (isAscii c && isAlphaNum c) || c == '_' ---------------------------------------------------------------------- -- prolog variables createLogicalVariable :: Int -> CId createLogicalVariable n = mkCId (logicalVariablePrefix ++ show n) isLogicalVariable :: String -> Bool isLogicalVariable = isPrefixOf logicalVariablePrefix logicalVariablePrefix :: String logicalVariablePrefix = "X" ---------------------------------------------------------------------- -- alpha convert variables to (unique) logical variables -- * this is needed if we want to translate variables to Prolog variables -- * used for abstract syntax, not concrete -- * not (yet?) used for variables bound in pattern equations type ConvertEnv = (Int, [(CId,CId)]) emptyEnv :: ConvertEnv emptyEnv = (0, []) class AlphaConvert a where alphaConvert :: ConvertEnv -> a -> (ConvertEnv, a) instance AlphaConvert a => AlphaConvert [a] where alphaConvert env [] = (env, []) alphaConvert env (a:as) = (env'', a':as') where (env', a') = alphaConvert env a (env'', as') = alphaConvert env' as instance AlphaConvert Type where alphaConvert env@(_,subst) (DTyp hypos cat args) = ((ctr,subst), DTyp hypos' cat args') where (env', hypos') = mapAccumL alphaConvertHypo env hypos ((ctr,_), args') = alphaConvert env' args alphaConvertHypo env (b,x,typ) = ((ctr+1,(x,x'):subst), (b,x',typ')) where ((ctr,subst), typ') = alphaConvert env typ x' = createLogicalVariable ctr instance AlphaConvert Expr where alphaConvert (ctr,subst) (EAbs b x e) = ((ctr',subst), EAbs b x' e') where ((ctr',_), e') = alphaConvert (ctr+1,(x,x'):subst) e x' = createLogicalVariable ctr alphaConvert env (EApp e1 e2) = (env'', EApp e1' e2') where (env', e1') = alphaConvert env e1 (env'', e2') = alphaConvert env' e2 alphaConvert env expr@(EFun i) = (env, maybe expr EFun (lookup i (snd env))) alphaConvert env expr = (env, expr) -- pattern variables are not alpha converted -- (but they probably should be...) instance AlphaConvert Equation where alphaConvert env@(_,subst) (Equ patterns result) = ((ctr,subst), Equ patterns result') where ((ctr,_), result') = alphaConvert env result