summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhallgren <hallgren@chalmers.se>2015-01-06 16:48:03 +0000
committerhallgren <hallgren@chalmers.se>2015-01-06 16:48:03 +0000
commitcbd873839b98b107cdb7afca7aa687f7d775d371 (patch)
tree072925474425c19226e11339a6d4e891b957e58e
parent35c11d5f5a2cffa40ef5a5dc2d6ba962b7df3cce (diff)
More work on translating linearization functions to Haskell
Many Phrasebook languages can now be converted to compilable Haskell code. Some languages (Fre, Hin, Snd, Urd) generate too much Haskell code to be practically useful (e.g. 338MB for Fre). One language (Fin) took too long to convert to Haskell. One language (Pes) has problems with name clashes in the generated Haskell code. STILL TODO: - variants - pre { ... } - reduce code duplication for large tables - generate qualified names to avoid name clashes
-rw-r--r--src/compiler/GF/Compile/ConcreteToHaskell.hs135
1 files changed, 93 insertions, 42 deletions
diff --git a/src/compiler/GF/Compile/ConcreteToHaskell.hs b/src/compiler/GF/Compile/ConcreteToHaskell.hs
index a52d00e14..783cce9b8 100644
--- a/src/compiler/GF/Compile/ConcreteToHaskell.hs
+++ b/src/compiler/GF/Compile/ConcreteToHaskell.hs
@@ -1,5 +1,5 @@
module GF.Compile.ConcreteToHaskell where
-import Data.List(sort,sortBy,(\\))
+import Data.List(sort,sortBy)
import Data.Function(on)
import qualified Data.Map as M
import qualified Data.Set as S
@@ -8,14 +8,13 @@ import GF.Data.Utilities(mapSnd)
import GF.Text.Pretty
import GF.Grammar.Grammar
import GF.Grammar.Lookup(lookupFunType,allParamValues,lookupOrigInfo,allOrigInfos)
-import GF.Grammar.Macros(typeForm,collectOp)
+import GF.Grammar.Macros(typeForm,collectOp,mkAbs,mkApp)
import GF.Grammar.Lockfield(isLockLabel)
-import GF.Grammar.Predef(cPredef)
+import GF.Grammar.Predef(cPredef,cInts)
import GF.Compile.Compute.Predef(predef)
import GF.Compile.Compute.Value(Predefined(..))
-import GF.Infra.Ident(Ident,identS) --,moduleNameS
+import GF.Infra.Ident(Ident,identS,prefixIdent) --,moduleNameS
import GF.Infra.Option
-import GF.Grammar.Printer(getAbs)
import GF.Compile.Compute.ConcreteNew(normalForm,resourceValues)
import Debug.Trace
@@ -93,18 +92,21 @@ toHaskell gId gr absname cenv (name,jment) =
CncCat (Just (L loc typ)) _ _ pprn _ ->
[(Nothing,("type"<+>"Lin"<>name,nf loc typ))]
CncFun (Just r@(cat,ctx,lincat)) (Just (L loc def)) pprn _ ->
- [(Just cat,("lin"<>cat<+>lhs,coerce lincat rhs))]
+-- trace (render (name<+>hcat[parens (x<>"::"<>t)|(_,x,t)<-ctx]<+>"::"<+>cat)) $
+ [(Just cat,("lin"<>cat<+>lhs,coerce [] lincat rhs))]
where
Ok abstype = lookupFunType gr absname name
(absctx,abscat,absargs) = typeForm abstype
- (xs,e') = getAbs (nf loc def)
- args = map snd xs
+ e' = unAbs (length params) $
+ nf loc (mkAbs params (mkApp def (map Vr args)))
+ params = [(b,prefixIdent "g" x)|(b,x,_)<-ctx]
+ args = map snd params
abs_args = map ("abs_"<>) args
lhs = if null args then aId name else parens (aId name<+>hsep abs_args)
rhs = foldr letlin e' (zip args absctx)
letlin (a,(_,_,at)) =
- Let (a,(Nothing,(App (con ("lin"++render at)) (con ("abs_"++render a)))))
+ Let (a,(Just (con ("Lin"++render at)),(App (con ("lin"++render at)) (con ("abs_"++render a)))))
AnyInd _ m -> case lookupOrigInfo gr (m,name) of
Ok (m,jment) -> toHaskell gId gr absname cenv (name,jment)
_ -> []
@@ -113,6 +115,11 @@ toHaskell gId gr absname cenv (name,jment) =
nf loc = normalForm cenv (L loc name)
aId n = "A."<>gId n
+ unAbs 0 t = t
+ unAbs n (Abs _ _ t) = unAbs (n-1) t
+ unAbs _ t = t
+
+
con = Cn . identS
tableTypes gr ts = S.unions (map tabtys ts)
@@ -127,13 +134,17 @@ paramTypes gr t =
case t of
RecType fs -> S.unions (map (paramTypes gr.snd) fs)
Table t1 t2 -> S.union (paramTypes gr t1) (paramTypes gr t2)
+ App tf ta -> S.union (paramTypes gr tf) (paramTypes gr ta)
Sort _ -> S.empty
+ EInt _ -> S.empty
Q q -> lookup q
QC q -> lookup q
+ FV ts -> S.unions (map (paramTypes gr) ts)
_ -> ignore
where
lookup q = case lookupOrigInfo gr q of
- Ok (_,ResOper _ (Just (L _ t))) -> paramTypes gr t
+ Ok (_,ResOper _ (Just (L _ t))) ->
+ S.insert q (paramTypes gr t)
Ok (_,ResParam {}) -> S.singleton q
_ -> ignore
@@ -152,23 +163,33 @@ records ts = S.unions (map recs ts)
labels = sort . filter (not . isLockLabel) . map fst
-coerce ty t =
+coerce env ty t =
case (ty,t) of
- (_,Let d t) -> Let d (coerce ty t)
- (_,FV ts) -> FV (map (coerce ty) ts)
- (Table ti tv,V _ ts) -> V ti (map (coerce tv) ts)
- (Table ti tv,T (TTyped _) cs) -> T (TTyped ti) (mapSnd (coerce tv) cs)
+ (_,Let d t) -> Let d (coerce (extend env d) ty t)
+ (_,FV ts) -> FV (map (coerce env ty) ts)
+ (Table ti tv,V _ ts) -> V ti (map (coerce env tv) ts)
+ (Table ti tv,T (TTyped _) cs) -> T (TTyped ti) (mapSnd (coerce env tv) cs)
(RecType rt,R r) ->
- R [(l,(Just ft,coerce ft f))|(l,(_,f))<-r,Just ft<-[lookup l rt]]
+ R [(l,(Just ft,coerce env ft f))|(l,(_,f))<-r,Just ft<-[lookup l rt]]
+ (RecType rt,Vr x)->
+ case lookup x env of
+ Just ty' | ty'/=ty ->
+ --trace ("coerce "++render ty'++" to "++render ty) $
+ App (to_rcon (map fst rt)) t
+ _ -> trace ("no coerce to "++render ty) t
+ _ -> t
_ -> t
-
+ where
+ extend env (x,(Just ty,rhs)) = (x,ty):env
+ extend env _ = env
convert gId = convert' False gId
convertA gId = convert' True gId
convert' atomic gId gr = if atomic then ppA else ppT
where
- ppT t =
+ ppT = ppT' False
+ ppT' loop t =
case t of
Let (x,(_,xt)) t -> sep ["let"<+>x<+>"="<+>ppT xt,"in"<+>ppT t]
Abs b x t -> "\\"<+>x<+>"->"<+>ppT t
@@ -176,33 +197,38 @@ convert' atomic gId gr = if atomic then ppA else ppT
T (TTyped ty) cs -> hang "\\case" 2 (vcat (map ppCase cs))
S t p -> hang (ppB t) 4 (ppA p)
C t1 t2 -> hang (ppA t1<+>"++") 4 (ppA t2)
- _ -> ppB t
+ _ -> ppB' loop t
ppCase (p,t) = hang (ppP p <+> "->") 4 (ppT t)
- ppB t =
+ ppB = ppB' False
+ ppB' loop t =
case t of
App f a -> ppB f<+>ppA a
R r -> rcon (map fst r)<+>fsep (fields r)
P t l -> ppB (proj l)<+>ppA t
FV [] -> "error"<+>doubleQuotes "empty variant"
- _ -> ppA t
+ _ -> ppA' loop t
+
+ ppA = ppA' False
- ppA t =
+ ppA' True t = error $ "Missing case in convert': "++show t
+ ppA' loop t =
case t of
Vr x -> pp x
Cn x -> pp x
Con c -> gId c
Sort k -> pp k
+ EInt n -> pp n
Q (m,n) -> if m==cPredef
then ppPredef n
else pp n
QC (m,n) -> gId n
K s -> token s
Empty -> pp "[]"
- FV (t:ts) -> ppA t -- !!
- Alts t _ -> ppA t -- !!!
- _ -> {-trace (show t) $-} parens (ppT t)
+ FV (t:ts) -> "{-variants-}"<>ppA t -- !!
+ Alts t _ -> "{-alts-}"<>ppA t -- !!!
+ _ -> parens (ppT' True t)
ppPredef n =
case predef n of
@@ -238,39 +264,58 @@ convert' atomic gId gr = if atomic then ppA else ppT
enumAll ty = case allParamValues gr ty of
Ok ts -> ts
-convType gId = ppT
+convType = convType' False
+convTypeA = convType' True
+
+convType' atomic gId = if atomic then ppA else ppT
where
- ppT t =
+ ppT = ppT' False
+ ppT' loop t =
case t of
Table ti tv -> ppB ti <+> "->" <+> ppT tv
- _ -> ppB t
+ _ -> ppB' loop t
- ppB t =
+ ppB = ppB' False
+ ppB' loop t =
case t of
RecType rt -> rcon (map fst rt)<+>fsep (fields rt)
- _ -> ppA t
+ App tf ta -> ppB tf <+> ppA ta
+ FV [] -> pp "({-empty variant-})"
+ _ -> ppA' loop t
- ppA t =
+ ppA = ppA' False
+ ppA' True t = error $ "Missing case in convType for: "++show t
+ ppA' loop t =
case t of
Sort k -> pp k
+ EInt n -> parens ("{-"<>n<>"-}") -- type level numeric literal
+ FV (t:ts) -> "{-variants-}"<>ppA t -- !!
QC (m,n) -> gId n
- _ -> {-trace (show t) $-} parens (ppT t)
+ Q (m,n) -> gId n
+ _ -> {-trace (show t) $-} parens (ppT' True t)
fields = map (ppA.snd) . sort . filter (not.isLockLabel.fst)
proj l = con ("proj_"++render l)
-rcon ls = con ("R"++concat (sort ['_':render l|l<-ls,not (isLockLabel l)]))
+rcon = con . rcon_name
+rcon_name ls = "R"++concat (sort ['_':render l|l<-ls,not (isLockLabel l)])
+to_rcon = con . ("to_"++) . rcon_name
recordType ls =
"data"<+>app<+>"="<+>app <+> "deriving (Eq,Ord,Show)" $+$
- vcat (map projection ls) $+$ ""
+ vcat (zipWith projection vs ls) $+$
+ to_rcon ls<+>"r"<+>"="<+>cn<+>fsep [parens (proj l<+>"r")|l<-ls] $+$ ""
where
- n = rcon ls
- app = n<+>ls
+ cn = rcon ls
+ -- Not all record labels are syntactically correct as type variables in Haskell
+ -- app = cn<+>ls
+ app = cn<+>hsep vs -- don't reuse record labels
+ vs = ["t"<>i|i<-[1..n]]
+ n = length ls
- projection l =
- hang ("instance"<+>"Has_"<>l<+>parens app<+>l<+>"where") 4
- (proj l<+>parens app<+>"="<+>l)
+ projection v l =
+ hang ("instance"<+>"Has_"<>l<+>parens app<+>v<+>"where") 4
+ (proj l<+>parens app<+>"="<+>v)
labelClass l =
hang ("class"<+>"Has_"<>l<+>"r"<+>"a"<+>"| r -> a"<+>"where") 4
@@ -279,13 +324,19 @@ labelClass l =
paramType gId gr q@(_,n) =
case lookupOrigInfo gr q of
Ok (m,ResParam (Just (L _ ps)) _)
- | True {-m/=cPredef && m/=moduleNameS "Prelude"-} ->
+ {- - | m/=cPredef && m/=moduleNameS "Prelude"-} ->
((S.singleton (m,n),argTypes ps),
- "data"<+>gId (snd q)<+>"="<+>
+ "data"<+>gId n<+>"="<+>
sep [fsep (punctuate " |" (map param ps)),
pp "deriving (Eq,Ord,Show)"])
+ Ok (m,ResOper _ (Just (L _ t)))
+ | m==cPredef && n==cInts ->
+ ((S.singleton (m,n),S.empty),pp "type GInts n = Int")
+ | otherwise ->
+ ((S.singleton (m,n),paramTypes gr t),
+ "type"<+>gId n<+>"="<+>convType gId t)
_ -> ((S.empty,S.empty),empty)
where
- param (n,ctx) = gId n<+>[convertA gId gr t|(_,_,t)<-ctx]
+ param (n,ctx) = gId n<+>[convTypeA gId t|(_,_,t)<-ctx]
argTypes = S.unions . map argTypes1
argTypes1 (n,ctx) = S.unions [paramTypes gr t|(_,_,t)<-ctx]