summaryrefslogtreecommitdiff
path: root/src/compiler/GF/Compile/PGFtoPython.hs
blob: d81a531e216de30c2c51d6afb23bec4721c0183b (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
----------------------------------------------------------------------
-- |
-- Module      : PGFtoPython
-- Maintainer  : Peter Ljunglöf
--
-- exports a GF grammar into a Python module
-----------------------------------------------------------------------------

module GF.Compile.PGFtoPython (pgf2python) where

import PGF.CId
import PGF.Data
import qualified PGF.Macros as M

import GF.Data.Operations

import qualified Data.Array.IArray as Array
import qualified Data.Set as Set
import qualified Data.Map as Map
import qualified Data.IntMap as IntMap
import Data.List (intersperse)

pgf2python :: PGF -> String
pgf2python pgf = ("# -*- coding: UTF-8 -*-" ++++
                  "# This file was automatically generated by GF" +++++
                  showCId name +++ "=" +++ 
                  pyDict 1 pyStr id [
                              ("flags", pyDict 2 pyCId pyLiteral (Map.assocs (gflags pgf))),
                              ("abstract", pyDict 2 pyStr id [
                                              ("name", pyCId name), 
                                              ("start", pyCId start), 
                                              ("flags", pyDict 3 pyCId pyLiteral (Map.assocs (aflags abs))),
                                              ("funs", pyDict 3 pyCId pyAbsdef (Map.assocs (funs abs)))
                                             ]),
                              ("concretes", pyDict 2 pyCId pyConcrete (Map.assocs cncs))
                             ] ++ "\n")
    where
      name  = absname pgf
      start = M.lookStartCat pgf
      abs = abstract pgf
      cncs = concretes pgf

pyAbsdef :: (Type, Int, Maybe [Equation], Double) -> String
pyAbsdef (typ, _, _, _) = pyTuple 0 id [pyCId cat, pyList 0 pyCId args]
    where (args, cat) = M.catSkeleton typ 

pyLiteral :: Literal -> String
pyLiteral (LStr s) = pyStr s
pyLiteral (LInt n) = show n
pyLiteral (LFlt d) = show d

pyConcrete :: Concr -> String
pyConcrete cnc = pyDict 3 pyStr id [
                  ("flags", pyDict 0 pyCId pyLiteral (Map.assocs (cflags cnc))),
                  ("printnames", pyDict 4 pyCId pyStr (Map.assocs (printnames cnc))),
                  ("lindefs", pyDict 4 pyCat (pyList 0 pyFun) (IntMap.assocs (lindefs cnc))),
                  ("productions", pyDict 4 pyCat pyProds (IntMap.assocs (productions cnc))),
                  ("cncfuns", pyDict 4 pyFun pyCncFun (Array.assocs (cncfuns cnc))),
                  ("sequences",  pyDict 4 pySeq pySymbols (Array.assocs (sequences cnc))),
                  ("cnccats", pyDict 4 pyCId pyCncCat (Map.assocs (cnccats cnc))),
                  ("size",  show (totalCats cnc))
                 ]
    where pyProds prods = pyList 5 pyProduction (Set.toList prods)
          pyCncCat (CncCat start end _) = pyList 0 pyCat [start..end]
          pyCncFun (CncFun f lins) = pyTuple 0 id [pyList 0 pySeq (Array.elems lins), pyCId f]
          pySymbols syms = pyList 0 pySymbol (Array.elems syms)

pyProduction :: Production -> String
pyProduction (PCoerce arg)       = pyTuple 0 id [pyStr "", pyList 0 pyCat [arg]]
pyProduction (PApply funid args) = pyTuple 0 id [pyFun funid, pyList 0 pyPArg args]
    where pyPArg (PArg [] fid) = pyCat fid
          pyPArg (PArg hypos fid) = pyTuple 0 pyCat (fid : map snd hypos)

pySymbol :: Symbol -> String
pySymbol (SymCat n l)    = pyTuple 0 show [n, l]
pySymbol (SymLit n l)    = pyDict 0 pyStr id [("lit", pyTuple 0 show [n, l])]
pySymbol (SymVar n l)    = pyDict 0 pyStr id [("var", pyTuple 0 show [n, l])]
pySymbol (SymKS ts)      = prTList "," (map pyStr ts)
pySymbol (SymKP ts alts) = pyDict 0 pyStr id [("pre", pyList 0 pyStr ts), ("alts", pyList 0 alt2py alts)]
    where alt2py (Alt ps ts) = pyTuple 0 (pyList 0 pyStr) [ps, ts]

----------------------------------------------------------------------
-- python helpers 

pyDict :: Int -> (k -> String) -> (v -> String) -> [(k, v)] -> String
pyDict n pk pv [] = "{}"
pyDict n pk pv kvlist = prCurly (pyIndent n ++ prTList ("," ++ pyIndent n) (map pyKV kvlist) ++ pyIndent n)
    where pyKV (k, v) = pk k ++ ":" ++ pv v

pyList :: Int -> (v -> String) -> [v] -> String
pyList n pv [] = "[]"
pyList n pv xs = prBracket (pyIndent n ++ prTList ("," ++ pyIndent n) (map pv xs) ++ pyIndent n)

pyTuple :: Int -> (v -> String) -> [v] -> String
pyTuple n pv [] = "()"
pyTuple n pv [x] = prParenth (pyIndent n ++ pv x ++ "," ++ pyIndent n)
pyTuple n pv xs = prParenth (pyIndent n ++ prTList ("," ++ pyIndent n) (map pv xs) ++ pyIndent n)

pyCat :: Int -> String
pyCat n = pyStr ('C' : show n)

pyFun :: Int -> String
pyFun n = pyStr ('F' : show n)

pySeq :: Int -> String
pySeq n = pyStr ('S' : show n)

pyStr :: String -> String
pyStr s = 'u' : prQuotedString s

pyCId :: CId -> String
pyCId = pyStr . showCId

pyIndent :: Int -> String
pyIndent n | n > 0 = "\n" ++ replicate n ' '
           | otherwise = ""