on master help sign in
Shuffle some code so that port deps get registered for DCE
commitc0aed6f75380259001b2ca2ae445285a8f735972 authorEvan Czaplicki <evancz@users.noreply.github.com> dateTue 4 Apr 2017, 20:07 (10 years ago) parent4c2e96a
7 files changed+371−288
elm-compiler.cabal+1−1 src/AST/Expression/Canonical.hs−26 src/AST/Expression/Optimized.hs+26−5 src/Generate/JavaScript/Expression.hs+10−12 src/Generate/JavaScript/Foreign.hs−240 src/Optimize.hs+22−4 src/Optimize/Port.hs+312
elm-compiler.cabal+1−1
@@ -94,7 +94,6 @@ Library
9494 Generate.JavaScript.BuiltIn,
9595 Generate.JavaScript.Effects,
9696 Generate.JavaScript.Expression,
97− Generate.JavaScript.Foreign,
9897 Generate.JavaScript.Helpers,
9998 Generate.JavaScript.Literal,
10099 Generate.JavaScript.Variable,
@@ -106,6 +105,7 @@ Library
106105 Optimize.DecisionTree,
107106 Optimize.Environment,
108107 Optimize.Inline,
108+ Optimize.Port,
109109 Parse.Declaration,
110110 Parse.Expression,
111111 Parse.Helpers,
src/AST/Expression/Canonical.hs−26
@@ -11,7 +11,6 @@ module AST.Expression.Canonical
1111 where
1212
1313
14−import Data.Binary
1514import Data.Monoid ((<>))
1615import Data.Text (Text)
1716import qualified Data.Text.Lazy as LText
@@ -161,28 +160,3 @@ collectLambdas lexpr@(A.A _ expr) =
161160
162161 _ ->
163162 ([], lexpr)
164−
165−
166−
167−-- BINARY
168−
169−
170−instance Binary Main where
171− put main =
172− case main of
173− VDom ->
174− putWord8 0
175−
176− NoFlags ->
177− putWord8 1
178−
179− Flags tipe ->
180− putWord8 2 >> put tipe
181−
182− get =
183− do word <- getWord8
184− case word of
185− 0 -> pure VDom
186− 1 -> pure NoFlags
187− 2 -> pure Flags <*> get
188− _ -> error "problem getting Can.Main binary"
src/AST/Expression/Optimized.hs+26−5
@@ -3,6 +3,7 @@ module AST.Expression.Optimized
33 ( Decl(..)
44 , Def(..)
55 , Expr(..)
6+ , Main(..)
67 , Decider(..), Choice(..)
78 )
89 where
@@ -14,10 +15,8 @@ import qualified Data.Set as Set
1415import Data.Text (Text)
1516
1617import qualified AST.Effects as Effects
17−import qualified AST.Expression.Canonical as Can
1818import qualified AST.Literal as Literal
1919import qualified AST.Module.Name as ModuleName
20−import qualified AST.Type as Type
2120import qualified AST.Variable as Var
2221import qualified Optimize.DecisionTree as DT
2322import qualified Reporting.Region as R
@@ -67,13 +66,19 @@ data Expr
6766 | Record [(Text, Expr)]
6867 | Cmd ModuleName.Canonical Effects.ManagerType
6968 | Sub ModuleName.Canonical Effects.ManagerType
70− | OutgoingPort Text Type.Canonical
71− | IncomingPort Text Type.Canonical
72− | Program Can.Main Expr
69+ | OutgoingPort Text Expr
70+ | IncomingPort Text Expr
71+ | Program Main Expr
7372 | GLShader Text
7473 | Crash ModuleName.Canonical R.Region (Maybe Expr)
7574
7675
76+data Main
77+ = VDom
78+ | NoFlags
79+ | Flags Expr
80+
81+
7782data Decider a
7883 = Leaf a
7984 | Chain
@@ -179,6 +184,22 @@ instance Binary Expr where
179184 Crash a b c -> putWord8 22 >> put a >> put b >> put c
180185
181186
187+instance Binary Main where
188+ put main =
189+ case main of
190+ VDom -> putWord8 0
191+ NoFlags -> putWord8 1
192+ Flags expr -> putWord8 2 >> put expr
193+
194+ get =
195+ do word <- getWord8
196+ case word of
197+ 0 -> pure VDom
198+ 1 -> pure NoFlags
199+ 2 -> liftM Flags get
200+ _ -> error "problem getting Can.Main binary"
201+
202+
182203instance (Binary a) => Binary (Decider a) where
183204 get =
184205 do word <- getWord8
src/Generate/JavaScript/Expression.hs+10−12
@@ -13,7 +13,6 @@ import Data.Monoid ((<>))
1313import qualified Data.Text as Text
1414import Data.Text (Text)
1515
16−import qualified AST.Expression.Canonical as Can
1716import AST.Expression.Optimized as Opt
1817import qualified AST.Literal as L
1918import qualified AST.Module.Name as ModuleName
@@ -21,7 +20,6 @@ import qualified AST.Variable as V
2120import Generate.JavaScript.Helpers as Help
2221import qualified Generate.JavaScript.Builder as JS
2322import qualified Generate.JavaScript.BuiltIn as BuiltIn
24−import qualified Generate.JavaScript.Foreign as Foreign
2523import qualified Generate.JavaScript.Literal as Literal
2624import qualified Generate.JavaScript.Variable as Var
2725import Generate.JavaScript.Variable (Generator)
@@ -200,12 +198,12 @@ generateCode expr =
200198 Sub moduleName _ ->
201199 JsExpr <$> BuiltIn.effect moduleName
202200
203− OutgoingPort name tipe ->
204− do encoder <- Foreign.encode tipe
205− JsExpr <$> BuiltIn.outgoingPort name encoder
201+ OutgoingPort name encoder ->
202+ do jsEncoder <- generateJsExpr encoder
203+ JsExpr <$> BuiltIn.outgoingPort name jsEncoder
206204
207− IncomingPort name tipe ->
208− do jsDecoder <- generateJsExpr (Foreign.decode tipe)
205+ IncomingPort name decoder ->
206+ do jsDecoder <- generateJsExpr decoder
209207 JsExpr <$> BuiltIn.incomingPort name jsDecoder
210208
211209 Program kind body ->
@@ -224,21 +222,21 @@ generateCode expr =
224222-- PROGRAMS
225223
226224
227−generateProgram :: Can.Main -> Opt.Expr -> Generator Code
225+generateProgram :: Opt.Main -> Opt.Expr -> Generator Code
228226generateProgram kind body =
229227 case kind of
230− Can.VDom ->
228+ Opt.VDom ->
231229 do html <- generateJsExpr body
232230 func <- BuiltIn.staticProgram
233231 jsExpr (func <| html)
234232
235− Can.NoFlags ->
233+ Opt.NoFlags ->
236234 do almostProgram <- generateJsExpr body
237235 jsExpr (JS.Call almostProgram [])
238236
239− Can.Flags tipe ->
237+ Opt.Flags decoder ->
240238 do almostProgram <- generateJsExpr body
241− flagDecoder <- generateJsExpr (Foreign.decode tipe)
239+ flagDecoder <- generateJsExpr decoder
242240 jsExpr (almostProgram <| flagDecoder)
243241
244242
src/Generate/JavaScript/Foreign.hsdeleted−240
@@ -1,240 +0,0 @@
1−{-# OPTIONS_GHC -Wall #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−module Generate.JavaScript.Foreign (encode, decode) where
4−
5−import Prelude hiding (maybe)
6−import Control.Monad (zipWithM)
7−import qualified Data.List as List
8−import qualified Data.Text as Text
9−import Data.Text (Text)
10−
11−import qualified AST.Expression.Optimized as Opt
12−import qualified AST.Literal as Literal
13−import qualified AST.Module.Name as ModuleName
14−import qualified AST.Type as T
15−import qualified AST.Variable as Var
16−import qualified Generate.JavaScript.Builder as JS
17−import qualified Generate.JavaScript.Helpers as JS (function, ref)
18−import Generate.JavaScript.Helpers ((<|), (==>))
19−import qualified Generate.JavaScript.Variable as JS (Generator, global)
20−
21−
22−
23−-- ENCODE
24−
25−
26−encode :: T.Canonical -> JS.Generator JS.Expr
27−encode tipe =
28− do js <- encodeHelp tipe (JS.ref "v")
29− return $ JS.function ["v"] [ JS.Return (Just js) ]
30−
31−
32−encodeHelp :: T.Canonical -> JS.Expr -> JS.Generator JS.Expr
33−encodeHelp tipe expr =
34− case tipe of
35− T.Aliased _ args t ->
36− encodeHelp (T.dealias args t) expr
37−
38− T.Lambda _ _ ->
39− error "encodeHelp: function"
40−
41− T.Var _ ->
42− error "encodeHelp: type variable"
43−
44− T.Type name
45− | Var.isPrim "Float" name -> pure expr
46− | Var.isPrim "Int" name -> pure expr
47− | Var.isPrim "Bool" name -> pure expr
48− | Var.isPrim "String" name -> pure expr
49− | Var.isJson name -> pure expr
50− | Var.isTuple name -> pure JS.Null
51− | otherwise -> error "encodeHelp: bad type"
52−
53− T.App (T.Type name) [arg]
54− | Var.isMaybe name -> fromMaybe arg expr
55− | Var.isList name -> fromList arg expr
56− | Var.isArray name -> fromArray arg expr
57− | otherwise -> error "encodeHelp: bad union type"
58−
59− T.App (T.Type name) args
60− | Var.isTuple name -> fromTuple args expr
61−
62− T.App _ _ ->
63− error "encodeHelp: bad union type"
64−
65− T.Record _ (Just _) ->
66− error "encodeHelp: bad record"
67−
68− T.Record fields Nothing ->
69− let
70− convert (k, t) =
71− (==>) k <$> encodeHelp t (JS.DotRef expr (JS.Id k))
72− in
73− JS.Object <$> traverse convert fields
74−
75−
76−fromMaybe :: T.Canonical -> JS.Expr -> JS.Generator JS.Expr
77−fromMaybe tipe expr =
78− do js <- encodeHelp tipe (JS.DotRef expr (JS.Id "_0"))
79− let isNothing = JS.Infix JS.OpStrictEq (JS.DotRef expr (JS.Id "ctor")) (JS.String "Nothing")
80− return $ JS.If isNothing JS.Null js
81−
82−
83−fromList :: T.Canonical -> JS.Expr -> JS.Generator JS.Expr
84−fromList tipe expr =
85− do let var = Var.Global (ModuleName.inCore "Elm.Kernel.List") "toArray"
86− toArray <- JS.global var
87− encoder <- encode tipe
88− return $ JS.DotRef (toArray <| expr) (JS.Id "map") <| encoder
89−
90−
91−fromArray :: T.Canonical -> JS.Expr -> JS.Generator JS.Expr
92−fromArray tipe expr =
93− do let var = Var.Global (ModuleName.inCore "Elm.Kernel.Array") "toJSArray"
94− toArray <- JS.global var
95− encoder <- encode tipe
96− return $ JS.DotRef (toArray <| expr) (JS.Id "map") <| encoder
97−
98−
99−fromTuple :: [T.Canonical] -> JS.Expr -> JS.Generator JS.Expr
100−fromTuple types expr =
101− let
102− convert subType n =
103− encodeHelp subType $ JS.DotRef expr (JS.Id (Text.pack ('_':show n)))
104− in
105− JS.Array <$> zipWithM convert types [ 0 .. length types ]
106−
107−
108−
109−-- SUBSCRIPTIONS
110−
111−
112−decode :: T.Canonical -> Opt.Expr
113−decode tipe =
114− case tipe of
115− T.Lambda _ _ ->
116− error "functions should not be allowed through input ports"
117−
118− T.Var _ ->
119− error "type variables should not be allowed through input ports"
120−
121− T.Aliased _ args t ->
122− decode (T.dealias args t)
123−
124− T.Type name
125− | Var.isPrim "Float" name -> to "float"
126− | Var.isPrim "Int" name -> to "int"
127− | Var.isPrim "Bool" name -> to "bool"
128− | Var.isPrim "String" name -> to "string"
129− | Var.isJson name -> to "value"
130− | Var.isTuple name -> toTuple0
131− | otherwise -> error "decode: bad type"
132−
133− T.App (T.Type name) [arg]
134− | Var.isMaybe name -> toMaybe arg
135− | Var.isList name -> to "list" <== [decode arg]
136− | Var.isArray name -> to "array" <== [decode arg]
137− | otherwise -> error "decode: bad union type"
138−
139− T.App (T.Type name) args
140− | Var.isTuple name -> toTuple args
141−
142− T.App _ _ ->
143− error "decode: bad union type"
144−
145− T.Record _ (Just _) ->
146− error "decode: bad record"
147−
148− T.Record fields Nothing ->
149− toRecord fields
150−
151−
152−-- DECODE HELPERS
153−
154−
155−to :: Text -> Opt.Expr
156−to name =
157− Opt.VarGlobal (Var.Global jsonDecode name)
158−
159−
160−jsonDecode :: ModuleName.Canonical
161−jsonDecode =
162− ModuleName.inCore "Json.Decode"
163−
164−
165−field :: Text -> Opt.Expr -> Opt.Expr
166−field name decoder =
167− to "field" <== [ Opt.Literal (Literal.Str name), decoder ]
168−
169−
170−index :: Int -> Opt.Expr -> Opt.Expr
171−index i decoder =
172− to "index" <== [ Opt.Literal (Literal.IntNum i), decoder ]
173−
174−
175−(<==) :: Opt.Expr -> [Opt.Expr] -> Opt.Expr
176−(<==) func args =
177− Opt.Call func args
178−
179−
180−
181−-- COMPLEX DECODE HELPERS
182−
183−
184−toMaybe :: T.Canonical -> Opt.Expr
185−toMaybe tipe =
186− let
187− maybe tag =
188− Opt.VarGlobal (Var.Global (ModuleName.inCore "Maybe") tag)
189− in
190− to "oneOf" <==
191− [ Opt.List
192− [ to "null" <== [ maybe "Nothing" ]
193− , to "map" <== [ maybe "Just", decode tipe ]
194− ]
195− ]
196−
197−
198−toTuple0 :: Opt.Expr
199−toTuple0 =
200− to "null" <== [ Opt.Ctor "_Tuple0" [] ]
201−
202−
203−toTuple :: [T.Canonical] -> Opt.Expr
204−toTuple types =
205− let
206− size =
207− length types
208−
209− pairs =
210− zipWith (,) [ 0 .. size - 1] types
211−
212− toVar i =
213− Text.pack ('x' : show i)
214−
215− makeTuple =
216− to "succeed" <==
217− [ Opt.Ctor
218− (Text.pack ("_Tuple" ++ show size))
219− (map (Opt.VarLocal . toVar . fst) pairs)
220− ]
221−
222− andThen (i, tipe) decoder =
223− to "andThen" <== [ Opt.Function [toVar i] decoder, index i (decode tipe) ]
224− in
225− List.foldr andThen makeTuple pairs
226−
227−
228−toRecord :: [(Text, T.Canonical)] -> Opt.Expr
229−toRecord fields =
230− let
231− toFieldExpr (key, _) =
232− (key, Opt.VarLocal key)
233−
234− finalDecoder =
235− to "succeed" <== [ Opt.Record (map toFieldExpr fields) ]
236−
237− andThen (key, tipe) decoder =
238− to "andThen" <== [ Opt.Function [key] decoder, field key (decode tipe) ]
239− in
240− List.foldr andThen finalDecoder fields
src/Optimize.hs+22−4
@@ -19,6 +19,7 @@ import qualified Optimize.Case as Case
1919import qualified Optimize.DecisionTree as DT
2020import qualified Optimize.Environment as Env
2121import qualified Optimize.Inline as Inline
22+import qualified Optimize.Port as Port
2223import qualified Reporting.Annotation as A
2324import qualified Reporting.Region as R
2425
@@ -281,13 +282,13 @@ optimizeExpr context annExpr@(A.A region expression) =
281282 Opt.Sub home <$> Env.registerEffects home manager
282283
283284 Can.OutgoingPort name tipe ->
284− pure (Opt.OutgoingPort name tipe)
285+ Opt.OutgoingPort name <$> Port.toEncoder tipe
285286
286287 Can.IncomingPort name tipe ->
287− pure (Opt.IncomingPort name tipe)
288+ Opt.IncomingPort name <$> Port.toDecoder tipe
288289
289− Can.Program kind expr ->
290− Opt.Program kind <$> justConvert expr
290+ Can.Program main expr ->
291+ Opt.Program <$> optimizeMain main <*> justConvert expr
291292
292293 Can.SaveEnv _ _ ->
293294 error "save_the_environment should never make it to optimization phase"
@@ -326,6 +327,23 @@ optimizeVariable region (Var.Canonical home name) =
326327
327328
328329
330+-- OPTIMIZE MAIN
331+
332+
333+optimizeMain :: Can.Main -> Env.Optimizer Opt.Main
334+optimizeMain main =
335+ case main of
336+ Can.VDom ->
337+ return Opt.VDom
338+
339+ Can.NoFlags ->
340+ return Opt.NoFlags
341+
342+ Can.Flags tipe ->
343+ Opt.Flags <$> Port.toDecoder tipe
344+
345+
346+
329347-- OPTIMIZE CASE BRANCHES
330348
331349
src/Optimize/Port.hsnew file+312
@@ -0,0 +1,312 @@
1+{-# OPTIONS_GHC -Wall #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+module Optimize.Port
4+ ( toEncoder
5+ , toDecoder
6+ )
7+ where
8+
9+
10+import Prelude hiding (maybe, null)
11+import Control.Monad (foldM, zipWithM)
12+import qualified Data.Text as Text
13+import Data.Text (Text)
14+
15+import qualified AST.Expression.Optimized as Opt
16+import qualified AST.Literal as Literal
17+import qualified AST.Module.Name as ModuleName
18+import qualified AST.Type as T
19+import qualified AST.Variable as Var
20+import qualified Optimize.DecisionTree as DT
21+import qualified Optimize.Environment as Env
22+
23+
24+
25+-- ENCODE
26+
27+
28+toEncoder :: T.Canonical -> Env.Optimizer Opt.Expr
29+toEncoder tipe =
30+ case tipe of
31+ T.Aliased _ args t ->
32+ toEncoder (T.dealias args t)
33+
34+ T.Lambda _ _ ->
35+ error "toEncoder: function"
36+
37+ T.Var _ ->
38+ error "toEncoder: type variable"
39+
40+ T.Type name
41+ | Var.isPrim "Float" name -> encode "float"
42+ | Var.isPrim "Int" name -> encode "int"
43+ | Var.isPrim "Bool" name -> encode "bool"
44+ | Var.isPrim "String" name -> encode "string"
45+ | Var.isJson name -> encode "string"
46+ | Var.isTuple name -> encode "null"
47+ | otherwise -> error "toEncoder: bad type"
48+
49+ T.App (T.Type name) [arg]
50+ | Var.isMaybe name -> encodeMaybe arg
51+ | Var.isList name -> encodeList arg
52+ | Var.isArray name -> encodeArray arg
53+ | otherwise -> error "toEncoder: bad union type"
54+
55+ T.App (T.Type name) args
56+ | Var.isTuple name -> encodeTuple args
57+
58+ T.App _ _ ->
59+ error "toEncoder: bad union type"
60+
61+ T.Record _ (Just _) ->
62+ error "toEncoder: bad record"
63+
64+ T.Record fields Nothing ->
65+ let
66+ convert (field, typ) =
67+ do encoder <- toEncoder typ
68+ return
69+ ( field
70+ , Opt.Call encoder [ Opt.Access (Opt.VarLocal "r") field ]
71+ )
72+ in
73+ do record <- traverse convert fields
74+ return $ Opt.Function ["r"] (Opt.Record record)
75+
76+
77+
78+-- ENCODE HELPERS
79+
80+
81+encodeMaybe :: T.Canonical -> Env.Optimizer Opt.Expr
82+encodeMaybe tipe =
83+ do null <- encode "null"
84+ encoder <- toEncoder tipe
85+
86+ let nothing = Var.inCore "Maybe" "Nothing"
87+ let test = (DT.Empty, DT.Constructor nothing)
88+ let just = Opt.Call encoder [ Opt.CtorAccess (Opt.VarLocal "m") 0 ]
89+ let leaf expr = Opt.Leaf (Opt.Inline expr)
90+
91+ return $ Opt.Function ["m"] $
92+ Opt.Case "m" (Opt.Chain [test] (leaf null) (leaf just)) []
93+
94+
95+encodeList :: T.Canonical -> Env.Optimizer Opt.Expr
96+encodeList tipe =
97+ do list <- encode "list"
98+ map_ <- core "List" "map"
99+ encoder <- toEncoder tipe
100+ return $
101+ Opt.Function ["xs"] $
102+ Opt.Call list [ Opt.Call map_ [ encoder, Opt.VarLocal "xs" ] ]
103+
104+
105+encodeArray :: T.Canonical -> Env.Optimizer Opt.Expr
106+encodeArray tipe =
107+ do array <- encode "array"
108+ map_ <- core "Array" "map"
109+ encoder <- toEncoder tipe
110+ return $
111+ Opt.Function ["xs"] $
112+ Opt.Call array [ Opt.Call map_ [ encoder, Opt.VarLocal "xs" ] ]
113+
114+
115+encodeTuple :: [T.Canonical] -> Env.Optimizer Opt.Expr
116+encodeTuple tipes =
117+ let
118+ convert tipe index =
119+ do encoder <- toEncoder tipe
120+ return $
121+ Opt.Call encoder [ Opt.CtorAccess (Opt.VarLocal "t") index ]
122+ in
123+ do list <- encode "list"
124+ entries <- zipWithM convert tipes [ 0 .. length tipes ]
125+ return $ Opt.Function ["t"] $ Opt.Call list entries
126+
127+
128+
129+-- DECODE
130+
131+
132+toDecoder :: T.Canonical -> Env.Optimizer Opt.Expr
133+toDecoder tipe =
134+ case tipe of
135+ T.Lambda _ _ ->
136+ error "functions should not be allowed through input ports"
137+
138+ T.Var _ ->
139+ error "type variables should not be allowed through input ports"
140+
141+ T.Aliased _ args t ->
142+ toDecoder (T.dealias args t)
143+
144+ T.Type name
145+ | Var.isPrim "Float" name -> decode "float"
146+ | Var.isPrim "Int" name -> decode "int"
147+ | Var.isPrim "Bool" name -> decode "bool"
148+ | Var.isPrim "String" name -> decode "string"
149+ | Var.isJson name -> decode "value"
150+ | Var.isTuple name -> decodeTuple0
151+ | otherwise -> error "toDecoder: bad type"
152+
153+ T.App (T.Type name) [arg]
154+ | Var.isMaybe name -> decodeMaybe arg
155+ | Var.isList name -> decodeList arg
156+ | Var.isArray name -> decodeArray arg
157+ | otherwise -> error "toDecoder: bad union type"
158+
159+ T.App (T.Type name) args
160+ | Var.isTuple name -> decodeTuple args
161+
162+ T.App _ _ ->
163+ error "toDecoder: bad union type"
164+
165+ T.Record _ (Just _) ->
166+ error "toDecoder: bad record"
167+
168+ T.Record fields Nothing ->
169+ decodeRecord fields
170+
171+
172+
173+-- DECODE MAYBE
174+
175+
176+decodeMaybe :: T.Canonical -> Env.Optimizer Opt.Expr
177+decodeMaybe tipe =
178+ do let nothing = Var.Global (ModuleName.inCore "Maybe") "Nothing"
179+ let just = Var.Global (ModuleName.inCore "Maybe") "Just"
180+
181+ Env.register nothing
182+ Env.register just
183+
184+ oneOf <- decode "oneOf"
185+ null <- decode "null"
186+ map_ <- decode "map"
187+
188+ subDecoder <- toDecoder tipe
189+
190+ return $
191+ Opt.Call oneOf
192+ [ Opt.List
193+ [ Opt.Call null [ Opt.VarGlobal nothing ]
194+ , Opt.Call map_ [ Opt.VarGlobal just, subDecoder ]
195+ ]
196+ ]
197+
198+
199+-- DECODE LIST
200+
201+
202+decodeList :: T.Canonical -> Env.Optimizer Opt.Expr
203+decodeList tipe =
204+ do list <- decode "list"
205+ decoder <- toDecoder tipe
206+ return $ Opt.Call list [ decoder ]
207+
208+
209+
210+-- DECODE ARRAY
211+
212+
213+decodeArray :: T.Canonical -> Env.Optimizer Opt.Expr
214+decodeArray tipe =
215+ do array <- decode "array"
216+ decoder <- toDecoder tipe
217+ return $ Opt.Call array [ decoder ]
218+
219+
220+
221+-- DECODE TUPLES
222+
223+
224+decodeTuple0 :: Env.Optimizer Opt.Expr
225+decodeTuple0 =
226+ do null <- decode "null"
227+ return (Opt.Call null [ Opt.Ctor "_Tuple0" [] ])
228+
229+
230+decodeTuple :: [T.Canonical] -> Env.Optimizer Opt.Expr
231+decodeTuple types =
232+ let
233+ size =
234+ length types
235+
236+ entries =
237+ zip [ 0 .. size - 1] types
238+
239+ tuple =
240+ Opt.Ctor
241+ (Text.pack ("_Tuple" ++ show size))
242+ (map (Opt.VarLocal . indexToName . fst) entries)
243+ in
244+ do succeed <- decode "succeed"
245+ foldM indexAndThen (Opt.Call succeed [tuple]) entries
246+
247+
248+indexToName :: Int -> Text
249+indexToName index =
250+ Text.pack ('x' : show index)
251+
252+
253+indexAndThen :: Opt.Expr -> (Int, T.Canonical) -> Env.Optimizer Opt.Expr
254+indexAndThen decoder (i, tipe) =
255+ do andThen <- decode "andThen"
256+ index <- decode "index"
257+ typeDecoder <- toDecoder tipe
258+ return $
259+ Opt.Call andThen
260+ [ Opt.Function [indexToName i] decoder
261+ , Opt.Call index [ Opt.Literal (Literal.IntNum i), typeDecoder ]
262+ ]
263+
264+
265+
266+-- DECODE RECORDS
267+
268+
269+decodeRecord :: [(Text, T.Canonical)] -> Env.Optimizer Opt.Expr
270+decodeRecord fields =
271+ let
272+ toFieldExpr (key, _) =
273+ (key, Opt.VarLocal key)
274+
275+ record =
276+ Opt.Record (map toFieldExpr fields)
277+ in
278+ do succeed <- decode "succeed"
279+ foldM fieldAndThen (Opt.Call succeed [record]) fields
280+
281+
282+fieldAndThen :: Opt.Expr -> (Text, T.Canonical) -> Env.Optimizer Opt.Expr
283+fieldAndThen decoder (key, tipe) =
284+ do andThen <- decode "andThen"
285+ field <- decode "field"
286+ typeDecoder <- toDecoder tipe
287+ return $
288+ Opt.Call andThen
289+ [ Opt.Function [key] decoder
290+ , Opt.Call field [ Opt.Literal (Literal.Str key), typeDecoder ]
291+ ]
292+
293+
294+
295+-- GLOBALS HELPERS
296+
297+
298+core :: Text -> Text -> Env.Optimizer Opt.Expr
299+core home name =
300+ do let var = Var.Global (ModuleName.inCore home) name
301+ Env.register var
302+ return (Opt.VarGlobal var)
303+
304+
305+encode :: Text -> Env.Optimizer Opt.Expr
306+encode name =
307+ core "Json.Encode" name
308+
309+
310+decode :: Text -> Env.Optimizer Opt.Expr
311+decode name =
312+ core "Json.Decode" name