mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-09-25 19:53:37 -06:00
207 lines
7.6 KiB
Haskell
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
|