summaryrefslogtreecommitdiff
path: root/src/GF/Compile/GrammarToCanon.hs
blob: ca3235a66b6c86bc589dcfd8d3d11045deafba6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
----------------------------------------------------------------------
-- |
-- Module      : GrammarToCanon
-- Maintainer  : AR
-- Stability   : (stable)
-- Portability : (portable)
--
-- > CVS $Date: 2005/02/18 19:21:08 $ 
-- > CVS $Author: peb $
-- > CVS $Revision: 1.16 $
--
-- Code generator from optimized GF source code to GFC.
-----------------------------------------------------------------------------

module GrammarToCanon (showGFC, 
		       redModInfo, redQIdent
		      ) where

import Operations
import Zipper
import Option
import Grammar
import Ident
import PrGrammar
import Modules
import Macros
import qualified AbsGFC as G
import qualified GFC as C
import MkGFC
---- import Alias
import qualified PrintGFC as P

import Monad

-- compilation of optimized grammars to canonical GF. AR 5/10/2001 -- 12/5/2003

-- | This is the top-level function printing a gfc file
showGFC :: SourceGrammar -> String
showGFC = err id id . liftM (P.printTree . grammar2canon) . redGrammar

-- | any grammar, first trying without dependent types
-- abstract syntax without dependent types
redGrammar :: SourceGrammar -> Err C.CanonGrammar
redGrammar (MGrammar gr) = liftM MGrammar $ mapM redModInfo $ filter active gr where
  active (_,m) = case typeOfModule m of
    MTInterface -> False
    _ -> True

redModInfo :: (Ident, SourceModInfo) -> Err (Ident, C.CanonModInfo)
redModInfo (c,info) = do
  c'    <- redIdent c
  info' <- case info of
    ModMod m -> do
      let isIncompl = not $ isCompleteModule m
      (e,os) <- if isIncompl then return ([],[]) else redExtOpen m ----
      flags <- mapM redFlag $ flags m 
      (a,mt0) <- case mtype m of
         MTConcrete a -> do
           a' <- redIdent a
           return (a', MTConcrete a') 
         MTAbstract -> return (c',MTAbstract) --- c' not needed
         MTResource -> return (c',MTResource) --- c' not needed
         MTInterface -> return (c',MTResource) ---- not needed
         MTInstance _ -> return (c',MTResource) --- c' not needed
         MTTransfer x y -> return (c',MTTransfer (om x) (om y)) --- c' not needed

      --- this generates empty GFC reosurce for interface and incomplete
      let js = if isIncompl then NT else jments m
          mt = mt0 ---- if isIncompl then MTResource else mt0

      defss <- mapM (redInfo a) $ tree2list $ js
      defs  <- return $ sorted2tree $ concat defss  -- sorted, but reduced
      return $ ModMod $ Module mt MSComplete flags e os defs
  return (c',info')
 where
   redExtOpen m = do
     e' <- case extends m of
       es -> mapM redIdent es
     os' <- mapM (\o -> case o of 
              OQualif q _ i -> liftM (OSimple q) (redIdent i)
              _ -> prtBad "cannot translate unqualified open in" c) $ opens m
     return (e',os')
   om = oSimple . openedModule --- normalizing away qualif

redInfo :: Ident -> (Ident,Info) -> Err [(Ident,C.Info)]
redInfo am (c,info) = errIn ("translating definition of" +++ prt c) $ do
  c' <- redIdent c 
  case info of
    AbsCat (Yes cont) pfs -> do
      let fs = case pfs of
                 Yes ts -> [(m,c) | Q m c <- ts]
                 _ -> []
      returns c' $ C.AbsCat cont fs
    AbsFun (Yes typ) pdf -> do
      let df = case pdf of
                 Yes t -> t  -- definition or "data"
                 _ -> Eqs [] -- primitive notion
      returns c' $ C.AbsFun typ df
    AbsTrans t -> 
      returns c' $ C.AbsTrans t

    ResParam (Yes ps) -> do
      ps' <- mapM redParam ps
      returns c' $ C.ResPar ps'

    CncCat pty ptr ppr -> case (pty,ptr,ppr) of
      (Yes ty, Yes (Abs _ t), Yes pr) -> do
        ty'  <- redCType ty
        trm' <- redCTerm t
        pr'  <- redCTerm pr 
        return [(c', C.CncCat ty' trm' pr')]
      _ -> prtBad "cannot reduce rule for" c
      
    CncFun mt ptr ppr -> case (mt,ptr,ppr) of
      (Just (cat,_), Yes trm, Yes pr) -> do
        cat' <- redIdent cat
        (xx,body,_) <- termForm trm
        xx'   <- mapM redArgvar xx
        body' <- errIn (prt body) $ redCTerm body ---- debug
        pr'   <- redCTerm pr 
        return [(c',C.CncFun (G.CIQ am cat') xx' body' pr')]
      _ -> prtBad ("cannot reduce rule" +++ show info +++ "for") c ---- debug

    AnyInd s b -> do
      b' <- redIdent b
      returns c' $ C.AnyInd s b'

    _ -> return [] --- retain some operations
 where
   returns f i = return [(f,i)]

redQIdent :: QIdent -> Err G.CIdent
redQIdent (m,c) = return $ G.CIQ m c

redIdent :: Ident -> Err Ident
redIdent x 
  | isWildIdent x = return $ identC "h_" --- needed in declarations
  | otherwise = return $ identC $ prt x ---

redFlag :: Option -> Err G.Flag
redFlag (Opt (f,[x])) = return $ G.Flg (identC f) (identC x)
redFlag o = Bad $ "cannot reduce option" +++ prOpt o

redDecl :: Decl -> Err G.Decl
redDecl (x,a) = liftM2 G.Decl (redIdent x) (redType a)

redType :: Type -> Err G.Exp
redType = redTerm

redTerm :: Type -> Err G.Exp
redTerm t = return $ rtExp t

-- resource

redParam :: Param -> Err G.ParDef
redParam (c,cont) = do
  c'    <- redIdent c
  cont' <- mapM (redCType . snd) cont
  return $ G.ParD c' cont'

redArgvar :: Ident -> Err G.ArgVar
redArgvar x = case x of
  IA (x,i)     -> return $ G.A  (identC x) (toInteger i)
  IAV (x,b,i) -> return $ G.AB (identC x) (toInteger b) (toInteger i)
  _ -> Bad $ "cannot reduce" +++ show x +++ "as argument variable"

redLindef :: Term -> Err G.Term
redLindef t = case t of
  Abs x b -> redCTerm b ---
  _ -> redCTerm t

redCType :: Type -> Err G.CType
redCType t = case t of
  RecType lbs -> do
    let (ls,ts) = unzip lbs
        ls' = map redLabel ls
    ts' <- mapM redCType ts
    return $ G.RecType $ map (uncurry G.Lbg) $ zip ls' ts'
  Table p v  -> liftM2 G.Table (redCType p) (redCType v)
  Q m c    -> liftM G.Cn $ redQIdent (m,c)
  QC m c   -> liftM G.Cn $ redQIdent (m,c)

  App (Q (IC "Predef") (IC "Ints")) (EInt n) -> return $ G.TInts (toInteger n)

  Sort "Str" -> return $ G.TStr
  _ -> prtBad "cannot reduce to canonical the type" t

redCTerm :: Term -> Err G.Term
redCTerm t = case t of
  Vr x -> checkAgain 
            (liftM G.Arg $ redArgvar x) 
            (liftM G.LI  $ redIdent x) --- for parametrize optimization
  App _ _ -> do  -- only constructor applications can remain
    (_,c,xx) <- termForm t
    xx' <- mapM redCTerm xx
    case c of
      QC p c -> liftM2 G.Con (redQIdent (p,c)) (return xx')
      _ -> prtBad "expected constructor head instead of" c
  Q p c  -> liftM G.I (redQIdent (p,c))
  QC p c -> liftM2 G.Con (redQIdent (p,c)) (return [])
  R rs     -> do
    let (ls,tts) = unzip rs
        ls' = map redLabel ls
    ts <- mapM (redCTerm . snd) tts
    return $ G.R $ map (uncurry G.Ass) $ zip ls' ts
  RecType [] -> return $ G.R [] --- comes out in parsing
  P tr l -> do
    tr' <- redCTerm tr
    return $ G.P tr' (redLabel l)
  T i cs     -> do
    ty  <- getTableType i
    ty' <- redCType ty
    let (ps,ts) = unzip cs
    ps' <- mapM redPatt ps
    ts' <- mapM redCTerm ts
    return $ G.T ty' $ map (uncurry G.Cas) $ zip (map singleton ps') ts'
  TSh i cs -> do
    ty  <- getTableType i
    ty' <- redCType ty
    let (pss,ts) = unzip cs
    pss' <- mapM (mapM redPatt) pss
    ts' <- mapM redCTerm ts
    return $ G.T ty' $ map (uncurry G.Cas) $ zip pss' ts'
  V ty ts     -> do
    ty' <- redCType ty
    ts' <- mapM redCTerm ts
    return $ G.V ty' ts'
  S u v -> liftM2 G.S (redCTerm u) (redCTerm v)
  K s   -> return $ G.K (G.KS s)
  EInt i -> return $ G.EInt $ toInteger i
  C u v -> liftM2 G.C (redCTerm u) (redCTerm v)
  FV ts -> liftM G.FV $ mapM redCTerm ts
---  Ready ss -> return $ G.Ready [redStr ss] --- obsolete

  Alts (d,vs) -> do ---
    d'  <- redCTermTok d
    vs' <- mapM redVariant vs
    return $ G.K $ G.KP d' vs'

  Empty -> return $ G.E

---  Strs ss -> return $ G.Strs [s | K s <- ss] ---

---- Glue obsolete in canon, should not occur here
  Glue x y -> redCTerm (C x y)

  _ -> Bad ("cannot reduce term" +++ prt t)

redPatt :: Patt -> Err G.Patt
redPatt p = case p of
  PP m c ps -> liftM2 G.PC (redQIdent (m,c)) (mapM redPatt ps) 
  PR rs -> do
    let (ls,tts) = unzip rs
        ls' = map redLabel ls
    ts <- mapM redPatt tts
    return $ G.PR $  map (uncurry G.PAss) $ zip ls' ts
  PT _ q -> redPatt q
  PInt i -> return $ G.PI (toInteger i)
  PV x -> liftM G.PV $ redIdent x --- for parametrize optimization
  _ -> prtBad "cannot reduce pattern" p

redLabel :: Label -> G.Label
redLabel (LIdent s) = G.L $ identC s
redLabel (LVar i)   = G.LV $ toInteger i

redVariant :: (Term, Term) -> Err G.Variant
redVariant (v,c) = do
  v' <- redCTermTok v
  c' <- redCTermTok c
  return $ G.Var v' c'

redCTermTok :: Term -> Err [String]
redCTermTok t = case t of
  K s   -> return [s]
  Empty -> return []
  C a b -> liftM2 (++) (redCTermTok a) (redCTermTok b)
  Strs ss -> return [s | K s <- ss] ---
  _ -> prtBad "cannot get strings from term" t