module GF.GFCC.Raw.ConvertGFCC (toGFCC,fromGFCC) where import GF.GFCC.DataGFCC import GF.GFCC.Raw.AbsGFCCRaw import GF.Data.Assoc import GF.Formalism.FCFG import GF.Formalism.Utilities (NameProfile(..), Profile(..), SyntaxForest(..)) import GF.Parsing.FCFG.PInfo (FCFPInfo(..), buildFCFPInfo) import qualified Data.Array as Array import Data.Map pgfMajorVersion, pgfMinorVersion :: Integer (pgfMajorVersion, pgfMinorVersion) = (1,0) -- convert parsed grammar to internal GFCC toGFCC :: Grammar -> GFCC toGFCC (Grm [ App (CId "pgf") (AInt v1 : AInt v2 : App a []:cs), App (CId "flags") gfs, ab@( App (CId "abstract") [ App (CId "fun") fs, App (CId "cat") cts ]), App (CId "concrete") ccs ]) = GFCC { absname = a, cncnames = [c | App c [] <- cs], gflags = fromAscList [(f,v) | App f [AStr v] <- gfs], abstract = let aflags = fromAscList [(f,v) | App f [AStr v] <- gfs] lfuns = [(f,(toType typ,toExp def)) | App f [typ, def] <- fs] funs = fromAscList lfuns lcats = [(c, Prelude.map toHypo hyps) | App c hyps <- cts] cats = fromAscList lcats catfuns = fromAscList [(cat,[f | (f, (DTyp _ c _,_)) <- lfuns, c==cat]) | (cat,_) <- lcats] in Abstr aflags funs cats catfuns, concretes = fromAscList [(lang, toConcr ts) | App lang ts <- ccs] } where toConcr :: [RExp] -> Concr toConcr = foldl add (Concr { cflags = empty, lins = empty, opers = empty, lincats = empty, lindefs = empty, printnames = empty, paramlincats = empty, parser = Nothing }) where add :: Concr -> RExp -> Concr add cnc (App (CId "flags") ts) = cnc { cflags = fromAscList [(f,v) | App f [AStr v] <- ts] } add cnc (App (CId "lin") ts) = cnc { lins = mkTermMap ts } add cnc (App (CId "oper") ts) = cnc { opers = mkTermMap ts } add cnc (App (CId "lincat") ts) = cnc { lincats = mkTermMap ts } add cnc (App (CId "lindef") ts) = cnc { lindefs = mkTermMap ts } add cnc (App (CId "printname") ts) = cnc { printnames = mkTermMap ts } add cnc (App (CId "param") ts) = cnc { paramlincats = mkTermMap ts } add cnc (App (CId "parser") ts) = cnc { parser = Just (toPInfo ts) } toPInfo :: [RExp] -> FCFPInfo toPInfo [App (CId "rules") rs, App (CId "startupcats") cs] = buildFCFPInfo (rules, cats) where rules = lmap toFRule rs cats = fromList [(c, lmap expToInt fs) | App c fs <- cs] toFRule :: RExp -> FRule toFRule (App (CId "rule") [n, App (CId "cats") (rt:at), App (CId "R") ls]) = FRule name args res lins where name = toFName n args = lmap expToInt at res = expToInt rt lins = mkArray [mkArray [toSymbol s | s <- l] | App (CId "S") l <- ls] toFName :: RExp -> FName toFName (App (CId "_A") [x]) = Name (CId "_") [Unify [expToInt x]] toFName (App f ts) = Name f (lmap toProfile ts) where toProfile :: RExp -> Profile (SyntaxForest CId) toProfile AMet = Unify [] toProfile (App (CId "_A") [t]) = Unify [expToInt t] toProfile (App (CId "_U") ts) = Unify [expToInt t | App (CId "_A") [t] <- ts] toProfile t = Constant (toSyntaxForest t) toSyntaxForest :: RExp -> SyntaxForest CId toSyntaxForest AMet = FMeta toSyntaxForest (App n ts) = FNode n [lmap toSyntaxForest ts] toSyntaxForest (AStr s) = FString s toSyntaxForest (AInt i) = FInt i toSyntaxForest (AFlt f) = FFloat f toSymbol :: RExp -> FSymbol toSymbol (App (CId "P") [c,n,l]) = FSymCat (expToInt c) (expToInt l) (expToInt n) toSymbol (AStr t) = FSymTok t toType :: RExp -> Type toType e = case e of App cat [App (CId "H") hypos, App (CId "X") exps] -> DTyp (lmap toHypo hypos) cat (lmap toExp exps) _ -> error $ "type " ++ show e toHypo :: RExp -> Hypo toHypo e = case e of App x [typ] -> Hyp x (toType typ) _ -> error $ "hypo " ++ show e toExp :: RExp -> Exp toExp e = case e of App (CId "App") [App fun [], App (CId "B") xs, App (CId "X") exps] -> DTr [x | App x [] <- xs] (AC fun) (lmap toExp exps) App (CId "Eq") eqs -> EEq [Equ (lmap toExp ps) (toExp v) | App (CId "E") (v:ps) <- eqs] App (CId "Var") [App i []] -> DTr [] (AV i) [] AMet -> DTr [] (AM 0) [] AInt i -> DTr [] (AI i) [] AFlt i -> DTr [] (AF i) [] AStr i -> DTr [] (AS i) [] _ -> error $ "exp " ++ show e toTerm :: RExp -> Term toTerm e = case e of App (CId "R") es -> R (lmap toTerm es) App (CId "S") es -> S (lmap toTerm es) App (CId "FV") es -> FV (lmap toTerm es) App (CId "P") [e,v] -> P (toTerm e) (toTerm v) App (CId "RP") [e,v] -> RP (toTerm e) (toTerm v) ---- App (CId "W") [AStr s,v] -> W s (toTerm v) App (CId "A") [AInt i] -> V (fromInteger i) App f [] -> F f AInt i -> C (fromInteger i) AMet -> TM "?" AStr s -> K (KS s) ---- _ -> error $ "term " ++ show e ------------------------------ --- from internal to parser -- ------------------------------ fromGFCC :: GFCC -> Grammar fromGFCC gfcc0 = Grm [ app "pgf" (AInt pgfMajorVersion:AInt pgfMinorVersion : App (absname gfcc) [] : lmap (flip App []) (cncnames gfcc)), app "flags" [App f [AStr v] | (f,v) <- toList (gflags gfcc `union` aflags agfcc)], app "abstract" [ app "fun" [App f [fromType t,fromExp d] | (f,(t,d)) <- toList (funs agfcc)], app "cat" [App f (lmap fromHypo hs) | (f,hs) <- toList (cats agfcc)] ], app "concrete" [App lang (fromConcrete c) | (lang,c) <- toList (concretes gfcc)] ] where gfcc = utf8GFCC gfcc0 app s = App (CId s) agfcc = abstract gfcc fromConcrete cnc = [ app "flags" [App f [AStr v] | (f,v) <- toList (cflags cnc)], app "lin" [App f [fromTerm v] | (f,v) <- toList (lins cnc)], app "oper" [App f [fromTerm v] | (f,v) <- toList (opers cnc)], app "lincat" [App f [fromTerm v] | (f,v) <- toList (lincats cnc)], app "lindef" [App f [fromTerm v] | (f,v) <- toList (lindefs cnc)], app "printname" [App f [fromTerm v] | (f,v) <- toList (printnames cnc)], app "param" [App f [fromTerm v] | (f,v) <- toList (paramlincats cnc)] ] ++ maybe [] (\p -> [fromPInfo p]) (parser cnc) fromType :: Type -> RExp fromType e = case e of DTyp hypos cat exps -> App cat [ App (CId "H") (lmap fromHypo hypos), App (CId "X") (lmap fromExp exps)] fromHypo :: Hypo -> RExp fromHypo e = case e of Hyp x typ -> App x [fromType typ] fromExp :: Exp -> RExp fromExp e = case e of DTr xs (AC fun) exps -> App (CId "App") [App fun [], App (CId "B") (lmap (flip App []) xs), App (CId "X") (lmap fromExp exps)] DTr [] (AV x) [] -> App (CId "Var") [App x []] DTr [] (AS s) [] -> AStr s DTr [] (AF d) [] -> AFlt d DTr [] (AI i) [] -> AInt (toInteger i) DTr [] (AM _) [] -> AMet ---- EEq eqs -> App (CId "Eq") [App (CId "E") (lmap fromExp (v:ps)) | Equ ps v <- eqs] _ -> error $ "exp " ++ show e fromTerm :: Term -> RExp fromTerm e = case e of R es -> app "R" (lmap fromTerm es) S es -> app "S" (lmap fromTerm es) FV es -> app "FV" (lmap fromTerm es) P e v -> app "P" [fromTerm e, fromTerm v] RP e v -> app "RP" [fromTerm e, fromTerm v] ---- W s v -> app "W" [AStr s, fromTerm v] C i -> AInt (toInteger i) TM _ -> AMet F f -> App f [] V i -> App (CId "A") [AInt (toInteger i)] K (KS s) -> AStr s ---- K (KP d vs) -> app "FV" (str d : [str v | Var v _ <- vs]) ---- where app = App . CId str v = app "S" (lmap AStr v) -- ** Parsing info fromPInfo :: FCFPInfo -> RExp fromPInfo p = app "parser" [ app "rules" [fromFRule rule | rule <- Array.elems (allRules p)], app "startupcats" [App f (lmap intToExp cs) | (f,cs) <- toList (startupCats p)] ] fromFRule :: FRule -> RExp fromFRule (FRule n args res lins) = app "rule" [fromFName n, app "cats" (intToExp res:lmap intToExp args), app "R" [app "S" [fromSymbol s | s <- Array.elems l] | l <- Array.elems lins] ] fromFName :: FName -> RExp fromFName n = case n of Name (CId "_") [p] -> fromProfile p Name f ps -> App f (lmap fromProfile ps) where fromProfile :: Profile (SyntaxForest CId) -> RExp fromProfile (Unify []) = AMet fromProfile (Unify [x]) = daughter x fromProfile (Unify args) = app "_U" (lmap daughter args) fromProfile (Constant forest) = fromSyntaxForest forest daughter n = app "_A" [intToExp n] fromSyntaxForest :: SyntaxForest CId -> RExp fromSyntaxForest FMeta = AMet -- FIXME: is there always just one element here? fromSyntaxForest (FNode n [args]) = App n (lmap fromSyntaxForest args) fromSyntaxForest (FString s) = AStr s fromSyntaxForest (FInt i) = AInt i fromSyntaxForest (FFloat f) = AFlt f fromSymbol :: FSymbol -> RExp fromSymbol (FSymCat c l n) = app "P" [intToExp c, intToExp n, intToExp l] fromSymbol (FSymTok t) = AStr t -- ** Utilities mkTermMap :: [RExp] -> Map CId Term mkTermMap ts = fromAscList [(f,toTerm v) | App f [v] <- ts] app :: String -> [RExp] -> RExp app = App . CId mkArray :: [a] -> Array.Array Int a mkArray xs = Array.listArray (0, length xs - 1) xs expToInt :: Integral a => RExp -> a expToInt (App (CId "neg") [AInt i]) = fromIntegral (negate i) expToInt (AInt i) = fromIntegral i expToStr :: RExp -> String expToStr (AStr s) = s intToExp :: Integral a => a -> RExp intToExp x | x < 0 = App (CId "neg") [AInt (fromIntegral (negate x))] | otherwise = AInt (fromIntegral x)