1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Generate.JavaScript.Foreign (encode, decode) where
5import Prelude hiding (maybe)
6import Control.Monad (zipWithM)
7import qualified Data.List as List
8import qualified Data.Text as Text
11import qualified AST.Expression.Optimized as Opt
12import qualified AST.Literal as Literal
13import qualified AST.Module.Name as ModuleName
14import qualified AST.Type as T
15import qualified AST.Variable as Var
16import qualified Generate.JavaScript.Builder as JS
17import qualified Generate.JavaScript.Helpers as JS (function, ref)
18import Generate.JavaScript.Helpers ((<|), (==>))
19import qualified Generate.JavaScript.Variable as JS (Generator, global)
26encode :: T.Canonical -> JS.Generator JS.Expr
28 do js <- encodeHelp tipe (JS.ref "v")
29 return $ JS.function ["v"] [ JS.Return (Just js) ]
32encodeHelp :: T.Canonical -> JS.Expr -> JS.Generator JS.Expr
36 encodeHelp (T.dealias args t) expr
39 error "encodeHelp: function"
42 error "encodeHelp: type variable"
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"
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"
59 T.App (T.Type name) args
60 | Var.isTuple name -> fromTuple args expr
63 error "encodeHelp: bad union type"
65 T.Record _ (Just _) ->
66 error "encodeHelp: bad record"
68 T.Record fields Nothing ->
71 (==>) k <$> encodeHelp t (JS.DotRef expr (JS.Id k))
73 JS.Object <$> traverse convert fields
76fromMaybe :: T.Canonical -> JS.Expr -> JS.Generator JS.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
83fromList :: T.Canonical -> JS.Expr -> JS.Generator JS.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
91fromArray :: T.Canonical -> JS.Expr -> JS.Generator JS.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
99fromTuple :: [T.Canonical] -> JS.Expr -> JS.Generator JS.Expr
100fromTuple types expr =
103 encodeHelp subType $ JS.DotRef expr (JS.Id (Text.pack ('_':show n)))
105 JS.Array <$> zipWithM convert types [ 0 .. length types ]
112decode :: T.Canonical -> Opt.Expr
116 error "functions should not be allowed through input ports"
119 error "type variables should not be allowed through input ports"
121 T.Aliased _ args t ->
122 decode (T.dealias args t)
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"
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"
139 T.App (T.Type name) args
140 | Var.isTuple name -> toTuple args
143 error "decode: bad union type"
145 T.Record _ (Just _) ->
146 error "decode: bad record"
148 T.Record fields Nothing ->
155to :: Text -> Opt.Expr
157 Opt.VarGlobal (Var.Global jsonDecode name)
160jsonDecode :: ModuleName.Canonical
162 ModuleName.inCore "Json.Decode"
165field :: Text -> Opt.Expr -> Opt.Expr
167 to "field" <== [ Opt.Literal (Literal.Str name), decoder ]
170index :: Int -> Opt.Expr -> Opt.Expr
172 to "index" <== [ Opt.Literal (Literal.IntNum i), decoder ]
175(<==) :: Opt.Expr -> [Opt.Expr] -> Opt.Expr
181-- COMPLEX DECODE HELPERS
184toMaybe :: T.Canonical -> Opt.Expr
188 Opt.VarGlobal (Var.Global (ModuleName.inCore "Maybe") tag)
192 [ to "null" <== [ maybe "Nothing" ]
193 , to "map" <== [ maybe "Just", decode tipe ]
200 to "null" <== [ Opt.Ctor "_Tuple0" [] ]
203toTuple :: [T.Canonical] -> Opt.Expr
210 zipWith (,) [ 0 .. size - 1] types
213 Text.pack ('x' : show i)
218 (Text.pack ("_Tuple" ++ show size))
219 (map (Opt.VarLocal . toVar . fst) pairs)
222 andThen (i, tipe) decoder =
223 to "andThen" <== [ Opt.Function [toVar i] decoder, index i (decode tipe) ]
225 List.foldr andThen makeTuple pairs
228toRecord :: [(Text, T.Canonical)] -> Opt.Expr
231 toFieldExpr (key, _) =
232 (key, Opt.VarLocal key)
235 to "succeed" <== [ Opt.Record (map toFieldExpr fields) ]
237 andThen (key, tipe) decoder =
238 to "andThen" <== [ Opt.Function [key] decoder, field key (decode tipe) ]
240 List.foldr andThen finalDecoder fields
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list