summaryrefslogtreecommitdiff
path: root/src/runtime/haskell/PGF/Linearize.hs
blob: 4a399f5e99d8995b27d3d4629aee3f27ae06db5f (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
module PGF.Linearize
            ( linearize
            , linearizeAll
            , linearizeAllLang
            , bracketedLinearize
            , tabularLinearizes
            ) where

import PGF.CId
import PGF.Data
import PGF.Macros
import PGF.Expr
import Data.Array.IArray
import Data.List
import Control.Monad
import qualified Data.Map as Map
import qualified Data.IntMap as IntMap
import qualified Data.Set as Set

--------------------------------------------------------------------
-- The API
--------------------------------------------------------------------

-- | Linearizes given expression as string in the language
linearize :: PGF -> Language -> Tree -> String
linearize pgf lang = concat . take 1 . map (unwords . concatMap flattenBracketedString . snd . untokn "" . (!0)) . linTree pgf lang

-- | The same as 'linearizeAllLang' but does not return
-- the language.
linearizeAll :: PGF -> Tree -> [String]
linearizeAll pgf = map snd . linearizeAllLang pgf

-- | Linearizes given expression as string in all languages
-- available in the grammar.
linearizeAllLang :: PGF -> Tree -> [(Language,String)]
linearizeAllLang pgf t = [(lang,linearize pgf lang t) | lang <- Map.keys (concretes pgf)]

-- | Linearizes given expression as a bracketed string in the language
bracketedLinearize :: PGF -> Language -> Tree -> BracketedString
bracketedLinearize pgf lang = head . concat . map (snd . untokn "" . (!0)) . linTree pgf lang

-- | Creates a table from feature name to linearization. 
-- The outher list encodes the variations
tabularLinearizes :: PGF -> CId -> Expr -> [[(String,String)]]
tabularLinearizes pgf lang e = map (zip lbls . map (unwords . concatMap flattenBracketedString . snd . untokn "") . elems)
                                   (linTree pgf lang e)
  where
    lbls = case unApp e of
             Just (f,_) -> let cat = valCat (lookType pgf f)
                           in case Map.lookup cat (cnccats (lookConcr pgf lang)) of
                                Just (CncCat _ _ lbls) -> elems lbls
                                Nothing                -> error "No labels"
             Nothing    -> error "Not function application"

--------------------------------------------------------------------
-- Implementation
--------------------------------------------------------------------

linTree :: PGF -> Language -> Expr -> [Array LIndex BracketedTokn]
linTree pgf lang e = 
  [amapWithIndex (\label -> Bracket_ fid label cat) lin | (_,(fid,cat,lin)) <- lin0 [] [] Nothing 0 e]
  where
    cnc   = lookMap (error "no lang") lang (concretes pgf)
    lp    = lproductions cnc
  
    lin0 xs ys mb_fid n_fid (EAbs _ x e)  = lin0 (showCId x:xs) ys mb_fid n_fid e
    lin0 xs ys mb_fid n_fid (ETyped e _)  = lin0 xs ys mb_fid n_fid e
    lin0 xs ys mb_fid n_fid e | null xs   = lin ys mb_fid n_fid e []
                              | otherwise = apply (xs ++ ys) mb_fid n_fid _B (e:[ELit (LStr x) | x <- xs])

    lin xs mb_fid n_fid (EApp e1 e2) es = lin xs mb_fid n_fid e1 (e2:es)
    lin xs mb_fid n_fid (ELit l)     [] = case l of
                                            LStr s -> return (n_fid+1,(n_fid,cidString,ss s))
                                            LInt n -> return (n_fid+1,(n_fid,cidInt   ,ss (show n)))
                                            LFlt f -> return (n_fid+1,(n_fid,cidFloat ,ss (show f)))
    lin xs mb_fid n_fid (EMeta i)    es = apply xs mb_fid n_fid _V (ELit (LStr ('?':show i)):es)
    lin xs mb_fid n_fid (EFun f)     es = apply xs mb_fid n_fid f  es
    lin xs mb_fid n_fid (EVar  i)    es = apply xs mb_fid n_fid _V (ELit (LStr (xs !! i))   :es)
    lin xs mb_fid n_fid (ETyped e _) es = lin xs mb_fid n_fid e es
    lin xs mb_fid n_fid (EImplArg e) es = lin xs mb_fid n_fid e es

    ss s = listArray (0,0) [[LeafKS [s]]]

    apply :: [String] -> Maybe FId -> FId -> CId -> [Expr] -> [(FId,(FId, CId, LinTable))]
    apply xs mb_fid n_fid f es =
      case Map.lookup f lp of
        Just prods -> do prod <- lookupProds mb_fid prods
                         case prod of
                           PApply funid fids -> do guard (length fids == length es)
                                                   (n_fid,args) <- descend n_fid (zip fids es)
                                                   let (CncFun fun lins) = cncfuns cnc ! funid
                                                       Just (DTyp _ cat _,_,_) = Map.lookup fun (funs (abstract pgf))
                                                   return (n_fid+1,(n_fid,cat,listArray (bounds lins) [computeSeq seqid args | seqid <- elems lins]))
                           PCoerce fid       -> apply xs (Just fid) n_fid f es
        Nothing    -> apply xs mb_fid n_fid _V [ELit (LStr ("[" ++ showCId f ++ "]"))]  -- fun without lin
      where
        lookupProds (Just fid) prods = maybe [] Set.toList (IntMap.lookup fid prods)
        lookupProds Nothing    prods
          | f == _B || f == _V       = []
          | otherwise                = [prod | (fid,set) <- IntMap.toList prods, prod <- Set.toList set]

        descend n_fid []            = return (n_fid,[])
        descend n_fid ((fid,e):fes) = do (n_fid,xx) <- lin0 [] xs (Just fid) n_fid e
                                         (n_fid,xxs) <- descend n_fid fes
                                         return (n_fid,xx:xxs)

        isApp (PApply _ _) = True
        isApp _            = False

        computeSeq :: SeqId -> [(FId,CId,LinTable)] -> [BracketedTokn]
        computeSeq seqid args = concatMap compute (elems seq)
          where
            seq = sequences cnc ! seqid

            compute (SymCat d r)    = getArg d r
            compute (SymLit d r)    = getArg d r
            compute (SymKS ts)      = [LeafKS ts]
            compute (SymKP ts alts) = [LeafKP ts alts]

            getArg d r
              | not (null arg_lin) = [Bracket_ fid r cat arg_lin]
              | otherwise          = arg_lin
              where
                arg_lin       = lin ! r
                (fid,cat,lin) = args !! d

amapWithIndex :: (IArray a e1, IArray a e2, Ix i) => (i -> e1 -> e2) -> a i e1 -> a i e2
amapWithIndex f arr = listArray (bounds arr) (map (uncurry f) (assocs arr))