mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-18 01:09:32 -06:00
303 lines
11 KiB
Haskell
303 lines
11 KiB
Haskell
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(..))
|
|
|
|
import qualified Data.Array as Array
|
|
import Data.Map
|
|
|
|
|
|
-- convert parsed grammar to internal GFCC
|
|
|
|
toGFCC :: Grammar -> GFCC
|
|
toGFCC (Grm [
|
|
App (CId "grammar") (AId 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 | AId 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 = foldl add (FCFPInfo {
|
|
allRules = error "FCFPInfo.allRules",
|
|
topdownRules = error "FCFPInfo.topdownRules",
|
|
epsilonRules = error "FCFPInfo.epsilonRules",
|
|
leftcornerCats = error "FCFPInfo.leftcornerCats",
|
|
leftcornerTokens = error "FCFPInfo.leftcornerTokens",
|
|
grammarCats = error "FCFPInfo.grammarCats",
|
|
grammarToks = error "FCFPInfo.grammarToks",
|
|
startupCats = error "FCFPInfo.startupCats"})
|
|
where
|
|
add :: FCFPInfo -> RExp -> FCFPInfo
|
|
add p (App (CId f) ts) =
|
|
case f of
|
|
"rules" -> p { allRules = mkArray (lmap toFRule ts) }
|
|
"topdownrules" -> p { topdownRules = toAssoc expToInt (lmap expToInt) ts }
|
|
"epsilonrules" -> p { epsilonRules = lmap expToInt ts }
|
|
"lccats" -> p { leftcornerCats = toAssoc expToInt (lmap expToInt) ts }
|
|
"lctoks" -> p { leftcornerTokens = toAssoc expToStr (lmap expToInt) ts }
|
|
"cats" -> p { grammarCats = lmap expToInt ts }
|
|
"toks" -> p { grammarToks = lmap expToStr ts }
|
|
"startupcats" -> p { startupCats = fromList [(c, lmap expToInt cs) | App c cs <- ts] }
|
|
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
|
|
|
|
toAssoc :: Ord a => (RExp -> a) -> ([RExp] -> b) -> [RExp] -> Assoc a b
|
|
toAssoc f g xs = listAssoc [(f k, g v) | App (CId "map") (k:v) <- xs]
|
|
|
|
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 fun [App (CId "B") xs, App (CId "X") exps] ->
|
|
DTr [x | AId x <- xs] (AC fun) (lmap toExp exps)
|
|
App (CId "Eq") eqs ->
|
|
EEq [Equ (lmap toExp ps) (toExp v) | App (CId "E") (v:ps) <- eqs]
|
|
AMet -> DTr [] (AM 0) []
|
|
AInt i -> DTr [] (AI i) []
|
|
AFlt i -> DTr [] (AF i) []
|
|
AStr i -> DTr [] (AS i) []
|
|
AId i -> DTr [] (AV 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)
|
|
AInt i -> C (fromInteger i)
|
|
AMet -> TM
|
|
AId f -> F f
|
|
App (CId "A") [AInt i] -> V (fromInteger i)
|
|
AStr s -> K (KS s) ----
|
|
_ -> error $ "term " ++ show e
|
|
|
|
------------------------------
|
|
--- from internal to parser --
|
|
------------------------------
|
|
|
|
fromGFCC :: GFCC -> Grammar
|
|
fromGFCC gfcc0 = Grm [
|
|
app "grammar" (AId (absname gfcc) : lmap AId (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 fun [App (CId "B") (lmap AId xs), App (CId "X") (lmap fromExp exps)]
|
|
DTr [] (AS s) [] -> AStr s
|
|
DTr [] (AF d) [] -> AFlt d
|
|
DTr [] (AV x) [] -> AId x
|
|
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 -> AId 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 "topdownrules" (fromAssoc intToExp (lmap intToExp) (topdownRules p)),
|
|
app "epsilonrules" (lmap intToExp (epsilonRules p)),
|
|
app "lccats" (fromAssoc intToExp (lmap intToExp) (leftcornerCats p)),
|
|
app "lctoks" (fromAssoc AStr (lmap intToExp) (leftcornerTokens p)),
|
|
app "cats" (lmap intToExp (grammarCats p)),
|
|
app "toks" (lmap AStr (grammarToks p)),
|
|
app "startupcats" [App f (lmap intToExp cs) | (f,cs) <- toList (startupCats p)]
|
|
]
|
|
|
|
fromAssoc :: Ord a => (a -> RExp) -> (b -> [RExp]) -> Assoc a b -> [RExp]
|
|
fromAssoc f g xs = [app "map" (f x:g y) | (x,y) <- aAssocs xs]
|
|
|
|
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)
|