Files
gf-core/src/compiler/api/GF/Compile/ConcreteToHaskell.hs
T

207 lines
7.6 KiB
Haskell

-- | Translate concrete syntax to Haskell
module GF.Compile.ConcreteToHaskell(concretes2haskell,concrete2haskell) where
import PGF2(Literal(..))
import Data.List(isPrefixOf,sort,sortOn)
import qualified Data.Map as Map
import GF.Text.Pretty
import GF.Grammar.Predef
import GF.Grammar.Grammar
import GF.Grammar.Macros
import GF.Infra.Ident
import GF.Infra.Option
import GF.Haskell as H
import GF.Compile.GrammarToCanonical
-- | Generate Haskell code for the all concrete syntaxes associated with
-- the named abstract syntax in given the grammar.
concretes2haskell opts absname gr = do
gr <- grammar2canonical opts absname gr
let abstr:concrs = modules gr
return [(filename,render80 $ concrete2haskell opts abstr concr)
| concr@(MN mn,_) <- concrs,
let filename = showIdent mn ++ ".hs" :: FilePath
]
-- | Generate Haskell code for the given concrete module.
-- The only options that make a difference are
-- @-haskell=noprefix@ and @-haskell=variants@.
concrete2haskell opts abstr@(absname,_) concr@(cncname,mi) =
haskPreamble absname cncname $$
vcat (
nl:Comment "--- Parameter types ---":
[paramDef id ps | (id,ResParam (Just (L _ ps)) _) <- Map.toList (jments mi)] ++
nl:Comment "--- Type signatures for linearization functions ---":
[signature id | (id,CncCat _ _ _ _ _) <- Map.toList (jments mi)] ++
nl:Comment "--- Linearization types ---":
[lincatDef id ty | (id,CncCat (Just (L _ ty)) _ _ _ _) <- Map.toList (jments mi)] ++
nl:Comment "--- Linearization functions ---":
concat (Map.elems lindefs) ++
nl:Comment "--- Type classes for projection functions ---":
-- map labelClass (S.toList labels) ++
nl:Comment "--- Record types ---":
[] -- concatMap recordType recs
)
where
nl = Comment ""
signature c = TypeSig lf (Fun abs (pure lin))
where
abs = tcon0 (prefixIdent "A." (gId c))
lin = tcon0 lc
lf = linfunName c
lc = lincatName c
gId :: Ident -> Ident
gId = (if haskellOption opts HaskellNoPrefix then id else prefixIdent "G")
va = haskellOption opts HaskellVariants
pure = if va then ListT else id
haskPreamble :: ModuleName -> ModuleName -> Doc
haskPreamble absname cncname =
"{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, LambdaCase #-}" $$
"module" <+> cncname <+> "where" $$
"import Prelude hiding (Ordering(..))" $$
"import Control.Applicative((<$>),(<*>))" $$
"import qualified" <+> absname <+> "as A" $$
"" $$
"-- | Token sequences, output form linearization functions" $$
"type Str = [Tok] -- token sequence" $$
"" $$
"-- | Tokens" $$
"data Tok = TK String | TP [([Prefix],Str)] Str | BIND | SOFT_BIND | SOFT_SPACE | CAPIT | ALL_CAPIT" $$
" deriving (Eq,Ord,Show)" $$
"" $$
"--- Standard definitions ---" $$
"linString (A.GString s) ="<+>pure "R_s [TK s]" $$
"linInt (A.GInt i) ="<+>pure "R_s [TK (show i)]" $$
"linFloat (A.GFloat x) ="<+>pure "R_s [TK (show x)]" $$
"" $$
"----------------------------------------------------" $$
"-- Automatic translation from GF to Haskell follows" $$
"----------------------------------------------------"
where
pure = if va then brackets else pp
paramDef id pvs = Data (conap0 (gId id)) (map paramCon pvs) derive
where
paramCon (id,ctxt) = ConAp (gId id) [tcon0 (gId cat) | (_,_,QC (_,cat)) <- ctxt]
derive = ["Eq","Ord","Show"]
convLinType (Sort s)
| s == cStr = tcon0 (identS "Str")
convLinType (QC (_,p)) = tcon0 (gId p)
convLinType (RecType lbls) = tcon (rcon' ls) (map convLinType ts)
where (ls,_,ts) = unzip3 $ sortOn (\(l,_,_)->l) lbls
convLinType (Table pt lt) = Fun (convLinType pt) (convLinType lt)
lincatDef c ty = tsyn0 (lincatName c) (convLinType ty)
lindefs =
Map.fromListWith (++)
[linDef id absctx cat lincat rhs |
(id,CncFun (Just (absctx,cat,_,lincat)) (Just (L _ rhs)) _ _) <- Map.toList (jments mi)]
linDef f absctx cat lincat rhs0 =
(cat,[Eqn (linfunName cat,lhs) rhs'])
where
lhs = [ConP (aId f) (map VarP abs_args)]
aId f = prefixIdent "A." (gId f)
--[C.Type absctx (TypeApp cat _)] = [t | FunDef f' t<-funs, f'==f]
(xs,rhs) = termFormCnc rhs0
abs_args = map abs_arg args
abs_arg = prefixIdent "abs_"
args = map (prefixIdent "g" . snd) xs
rhs' = lets (zipWith letlin args absctx)
(convert rhs)
where
vs = [(x,a)|((_,x),a)<-zip xs args]
letlin a acat =
(a,Ap (Var (linfunName acat)) (Var (abs_arg a)))
convert (Vr v) = Var (gId v)
convert (EInt n) = lit n
convert (EFloat d) = lit d
convert (K s) = single (Const "TK" `Ap` lit s)
convert Empty = List []
convert (App t1 t2) = Ap (convert t1) (convert t2)
convert (R lbls) = aps (rcon ls) (map (convert.snd) ts)
where (ls,ts) = unzip (sortOn fst lbls)
convert (P t lbl) = ap (proj lbl) (convert t)
convert (ExtR t1 t2) = Const "ExtR" -- TODO
convert (T _ cs) = LambdaCase (map ppCase cs)
where
ppCase (p,t) = (convertPatt p,convert t)
convert (V _ ts) = Const "V" -- TODO
convert (S t p)
| va = select_va (convert t) (convert p)
| otherwise = Ap (convert t) (convert p)
where
select_va (List [t]) (List [p]) = Op t "!" p
select_va (List [t]) p = Op t "!$" p
select_va t p = Op t "!*" p
convert (Q (_,id)) = single (Var id)
convert (QC (_,id)) = single (Var id)
convert (C t1 t2)
| va = concat_va (convert t1) (convert t2)
| otherwise = plusplus (convert t1) (convert t2)
where
concat_va (List [List ts1]) (List [List ts2]) = List [List (ts1++ts2)]
concat_va t1 t2 = Op t1 "+++" t2
convert (Glue t1 t2) = Const "Glue"
convert (FV ts)
| va = join (List (map convert ts))
| otherwise = case ts of
[] -> Const "error" `Ap` Const (show "empty variant")
(t:ts) -> convert t
where
join (List [x]) = x
join x = Const "concat" `Ap` x
convert (Alts def alts) = single (Const "TP" `Ap` List (map convAlt alts) `Ap` convert def)
where
convAlt (t1,t2) = Pair (convert t1) (convert t2)
convert (Strs ss) = List (map lit ss)
convert t = error (show t)
convertPatt (PC c ps) = ConP (gId c) (map convertPatt ps)
convertPatt (PP (_,c) ps) = ConP (gId c) (map convertPatt ps)
convertPatt (PV v)
| v == identW = WildP
| otherwise = VarP v
convertPatt (PR lbls) = ConP (rcon' ls) (map convertPatt ps)
where (ls,ps) = unzip $ sortOn fst lbls
convertPatt (PString s) = Lit s
convertPatt (PT _ p) = convertPatt p
convertPatt (PAs v p) = AsP v (convertPatt p)
convertPatt (PImplArg p) = convertPatt p
convertPatt (PTilde _) = WildP
convertPatt (PAlt _ _) = WildP -- TODO
convertPatt p = error (show p)
lit s = Const (show s) -- hmm
ap = if va then ap' else Ap
where
ap' (List [f]) x = fmap f x
ap' f x = Op f "<*>" x
fmap f (List [x]) = Ap f x
fmap f x = Op f "<$>" x
aps f [] = f
aps f (a:as) = aps (ap f a) as
proj = Var . identS . proj'
proj' (LIdent l) = "proj_" ++ showRawIdent l
rcon = Var . rcon'
rcon' = identS . rcon_name
rcon_name ls = "R"++concat (sort ['_':showRawIdent l | LIdent l <- ls])
lincatName,linfunName :: Ident -> Ident
lincatName c = prefixIdent "Lin" c
linfunName c = prefixIdent "lin" c