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
-- This module generates ConvertST instances like toValST
-- and fromValST as well as the functions toST and fromST.
module GenConvertST
  ( genConvInstances
  )
where

import           AbstractCurry.Types     hiding ( QName )
import           FlatCurry.Types         hiding ( Visibility(..) )
import           List                           ( nub )
import           Data.FiniteMap

import           State
import           StateMonad
import           Utilities
import           Translate
import           Lookup

-- Generates CovertST instances based on the information
-- added to the state by the plural transformation.
genConvInstances :: Monad m => OptState m ()
genConvInstances = do
  ftys <- gets funcTypes
  let qns = nub $ concatMap compareTypes ftys
  let lookupT (q1, q2) = do
        td1 <- lookupTypeDecl q1
        td2 <- lookupCTypeDecl q2
        case td2 of
          Prelude.Left  td  -> return (td1, translTypeDecl td)
          Prelude.Right ctd -> return (td1, ctd)
  tds <- mapM lookupT qns
  mapM_ (uncurry genConv) tds
  return ()

-- Generates ConvertST instances for a pair of types where
-- one is a FlatCurry type (from the original program) and
-- the other is a generated AbstractCurry data type.
genConv :: Monad m => TypeDecl -> CTypeDecl -> OptState m ()
genConv t1 t2 = case (t1, t2) of
  (Type qn1 _ _ _, CType qn2 _ _ _ _) ->
    if qn1 == qn2 then genBasic qn1 else genComplex t1 t2
  _ -> return ()

-- Generates a basic ConvertST instances for a data type.
-- Basic instances "convert" between the same types,
-- for example toValST_Int_Int
genBasic :: Monad m => QName -> OptState m ()
genBasic qn@(m, n) = do
  let qn' s = (m, s ++ "_" ++ n ++ "_" ++ n)
      typ f1 f2 =
        CQualType (CContext []) (CFuncType (f1 $ CTCons qn) (f2 $ CTCons qn))
      rule = CRule [] (CSimpleRhs (CSymbol ("Prelude", "id")) [])
      func qname = CFunc (qn' qname) 1 Public (typ id id) [rule]
  toSTRule   <- genRuleToST 0 (qn' "toValST")
  fromSTRule <- genRuleFromST 0 (qn' "fromValST")
  let func' f1 f2 qname r = CFunc (qn' qname) 1 Public (typ f1 f2) [r]
      funcs =
        [ func "toValST"
        , func "fromValST"
        , func' id    addST     "toST"   toSTRule
        , func' addST addValues "fromST" fromSTRule
        ]
  modify $ addCurryFDs funcs

genComplex :: Monad m => TypeDecl -> CTypeDecl -> OptState m ()
genComplex t1 t2 = case (t1, t2) of
  (Type qn1 _ tvs1 cds1, CType qn2 _ _ cds2 _) -> do
    let vcnt    = length tvs1
        valFunc = genFunc vcnt cds1 cds2 (qn1, qn2)
    toValSTFunc   <- valFunc ToValST
    fromValSTFunc <- valFunc FromValST
    toSTFunc      <- valFunc ToST
    fromSTFunc    <- valFunc FromST
    modify $ addCurryFDs [toValSTFunc, fromValSTFunc, toSTFunc, fromSTFunc]
  _ -> return ()

-- Represents the different ConvertST instances/functions
data STFunction = ToValST | FromValST | ToST | FromST

-- Generates a ConvertST instance or function
genFunc
  :: Monad m
  => Int -- Number of type variables
  -> [ConsDecl] -- Constructors of the FlatCurry type
  -> [CConsDecl] -- Constructors of the AbstractCurry type
  -> (QName, QName) -- Names of the types
  -> STFunction -- Which function to generate
  -> OptState m CFuncDecl
genFunc vcnt cds1 cds2 (qn1@(m, n1), qn2@(_, n2)) stf =
  let
    qn' = genQName m n1 n2
    eis = take vcnt evens
    ois = take vcnt odds
    funcType st cty1 cty2 cnstrs = CQualType
      (CContext cnstrs)
      (foldr CFuncType cty2 (argFuncTypes st ++ [cty1]))
    argFuncTypes st = map (argFuncType st) eis
    consType qn f is = f $ listToType qn (map (CTVar . translTVar) is)
    argFuncType f i =
      CFuncType (CTVar $ translTVar i) (f (CTVar . translTVar $ i + 1))
    genRules f insts = mapM (uncurry $ f vcnt insts) (zip cds1 cds2)
    funcDecl qn typ rules = CFunc qn (vcnt + 1) Public typ rules
  in
    case stf of
      ToValST -> do
        ftys  <- gets funcTypes
        rules <- genRules genRuleToValST (nub $ concatMap compareTypes ftys)
        let typ = funcType addST (consType qn1 id eis) (consType qn2 id ois) []
        return $ funcDecl (qn' "toValST") typ rules
      FromValST -> do
        ftys  <- gets funcTypes
        rules <- genRules genRuleFromValST
                          (map swap $ nub (concatMap compareTypes ftys))
        let typ = funcType id (consType qn2 id eis) (consType qn1 id ois) []
        return $ funcDecl (qn' "fromValST") typ rules
      ToST -> do
        rule <- genRuleToST vcnt (qn' "toValST")
        let typ =
              funcType addST (consType qn1 id eis) (consType qn2 addST ois) []
        return $ funcDecl (qn' "toST") typ [rule]
      FromST -> do
        rule   <- genRuleFromST vcnt (qn' "fromValST")
        tSTMap <- gets typeSTMap
        case lookupFM tSTMap qn2 of
          Just oqn ->
            let
              typ = funcType id
                             (consType qn2 addST eis)
                             (consType oqn addValues ois)
                             cnstrs
              cnstrs = map (\i -> (("ST", "NF"), CTVar $ translTVar i)) eis
            in
              return $ funcDecl (qn' "fromST") typ [rule]
          Nothing ->
            error $ "genFunc: Missing original data type for " ++ show qn2

genRuleToValST
  :: Monad m
  => Int -- Number of type variables
  -> [(QName, QName)] -- Pairs of type - ST type names
  -> ConsDecl
  -> CConsDecl
  -> OptState m CRule
genRuleToValST _ _ (FlatCurry.Types.Cons _ _ _ _) (CRecord _ _ _ _ _) =
  notImplemented "genRuleToValSt" "Record types"
genRuleToValST tvars insts (FlatCurry.Types.Cons qn ar _ tys) (CCons _ _ cqn _ _)
  = do
    m  <- gets currentModule
    vs <- freshVars tvars
    xs <- freshVars ar
    let iargs      = zip (nub $ concatMap typeVars tys) vs
        txs        = zip xs tys
        rule       = CRule (map CPVar vs ++ [CPComb qn (map CPVar xs)]) rhs
        genRuleExp = genRuleToValSTExpr m iargs insts
        rhs        = CSimpleRhs (listToExpr cqn (map genRuleExp txs)) []
    return rule

genRuleFromValST
  :: Monad m
  => Int -- Number of type variables
  -> [(QName, QName)] -- Pairs of type - ST type names
  -> ConsDecl
  -> CConsDecl
  -> OptState m CRule
genRuleFromValST _ _ (FlatCurry.Types.Cons _ _ _ _) (CRecord _ _ _ _ _) =
  notImplemented "genRuleFromValST" "Record types"
genRuleFromValST tvars insts (FlatCurry.Types.Cons qn ar _ _) (CCons _ _ cqn _ ctys)
  = do
    m  <- gets currentModule
    vs <- freshVars tvars
    xs <- freshVars ar
    let iargs = zip (nub $ concatMap ctypeVars ctys) vs
        txs   = zip xs ctys
        pat i = CPComb ("ST", "Val") [CPVar i]
        rule       = CRule (map CPVar vs ++ [CPComb cqn (map pat xs)]) rhs
        genRuleExp = genRuleFromValSTExpr m iargs insts
        rhs        = CSimpleRhs (listToExpr qn (map genRuleExp txs)) []
    return rule

genRuleToValSTExpr
  :: String -- Current module
  -> [(TVarIndex, CTVarIName)] -- Pairs of type variable - argument function variable
  -> [(QName, QName)] -- Pairs of type - ST type names
  -> (CTVarIName, TypeExpr) -- Pattern variable and its type
  -> CExpr
genRuleToValSTExpr m iargs insts (y, t) = CApply (genRuleExpr' t) (CVar y)
 where
  genRuleExpr' typ = case typ of
    TVar i -> case lookup i iargs of
      Just v -> CVar v
      Nothing ->
        error
          $  "genRuleToValSTExpr: Missing instance argument for variable "
          ++ show i
    FuncType _ _ ->
      notImplemented "genRuleToValSTExpr" "Higher-order functions"
    TCons qname@(_, n1) ts -> case lookup qname insts of
      Just (_, n2) ->
        let args   = map genRuleExpr' ts
            qname' = genQName m n1 n2 "toST"
        in  listToExpr qname' args
      Nothing ->
        error $ "genRuleToValSTExpr: Missing instance for " ++ show qname
    ForallType _ ty -> genRuleExpr' ty

genRuleFromValSTExpr
  :: String -- Current module
  -> [(CTVarIName, CTVarIName)] -- Pairs of type variable - argument function variable
  -> [(QName, QName)] -- Pairs of type - ST type names
  -> (CTVarIName, CTypeExpr) -- Pattern variable and its type
  -> CExpr
genRuleFromValSTExpr m iargs insts (y, t) = CApply (genRuleExpr' t) (CVar y)
 where
  genRuleExpr' typ = case typ of
    CTVar i -> case lookup i iargs of
      Just v -> CVar v
      Nothing ->
        error
          $  "genRuleFromValSTExpr: Missing instance argument for variable "
          ++ show i
    CFuncType _ _ ->
      notImplemented "genRuleFromValSTExpr" "Higher-order functions"
    CTCons qname@(_, n1) -> case lookup qname insts of
      Just (_, n2) -> CSymbol $ genQName m n2 n1 "fromValST"
      Nothing ->
        error $ "genRuleFromValSTExpr: Missing instance for " ++ show qname
    CTApply (CTCons ("ST", "ST")) x -> genRuleExpr' x
    CTApply f                     x -> CApply (genRuleExpr' f) (genRuleExpr' x)


genRuleToST :: Monad m => Int -> QName -> OptState m CRule
genRuleToST tvars qn = do
  vs <- freshVars tvars
  let rule   = CRule (map CPVar vs) rhs
      uneval = CApply (CSymbol ("Prelude", ".")) (CSymbol ("ST", "Uneval"))
      exp    = CApply uneval (listToExpr qn (map CVar vs))
      rhs    = CSimpleRhs exp []
  return rule

genRuleFromST :: Monad m => Int -> QName -> OptState m CRule
genRuleFromST tvars qn = do
  vs <- freshVars tvars
  let rule = CRule (map CPVar vs) rhs
      mape = listToExpr ("Prelude", "map") [listToExpr qn (map CVar vs)]
      exp  = listToExpr ("Prelude", ".") [mape, (CSymbol ("ST", "stValues"))]
      rhs  = CSimpleRhs exp []
  return rule