1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Generate.JavaScript
10import Prelude hiding (cycle)
11import qualified Data.ByteString.Builder as B
12import Data.Monoid ((<>))
13import qualified Data.List as List
15import qualified Data.Map as Map
16import qualified Data.Set as Set
18import qualified AST.Optimized as Opt
19import qualified AST.Module.Name as ModuleName
20import qualified Elm.Name as N
21import qualified Elm.Package as Pkg
22import qualified Generate.JavaScript.Builder as JS
23import qualified Generate.JavaScript.Expression as Expr
24import qualified Generate.JavaScript.Name as Name
32 = Mains [ModuleName.Canonical]
33 | Value ModuleName.Canonical N.Name
36generate :: Bool -> Name.Target -> Opt.Graph -> Roots -> Either [ModuleName.Canonical] B.Builder
37generate debug target (Opt.Graph mains nodes fields) roots =
40 Right $ stateToBuilder $
41 addGlobal (toMode debug target fields) nodes emptyState (Opt.Global home name)
44 generateMain (toMode debug target fields) nodes
45 <$> verifyMains mains modules
48toMode :: Bool -> Name.Target -> Map.Map N.Name Int -> Name.Mode
49toMode debug target fields =
53 Name.Prod target (Name.shortenFieldNames fields)
57-- GRAPH TRAVERSAL STATE
62 { _revBuilders :: [B.Builder]
63 , _seenGlobals :: Set.Set Opt.Global
72stateToBuilder :: State -> B.Builder
73stateToBuilder (State revBuilders _) =
74 List.foldl1' (\builder b -> b <> builder) revBuilders
82type Graph = Map.Map Opt.Global Opt.Node
85addGlobal :: Mode -> Graph -> State -> Opt.Global -> State
86addGlobal mode graph state@(State builders seen) global =
87 if Set.member global seen then
90 addGlobalHelp mode graph global $
91 State builders (Set.insert global seen)
94addGlobalHelp :: Mode -> Graph -> Opt.Global -> State -> State
95addGlobalHelp mode graph global state =
97 addDeps deps someState =
98 Set.foldl' (addGlobal mode graph) someState deps
100 case graph ! global of
101 Opt.Define expr deps ->
102 addStmt (addDeps deps state) (
103 var global (Expr.generate mode expr)
106 Opt.DefineTailFunc argNames body deps ->
107 addStmt (addDeps deps state) (
108 var global (Expr.generateFunction (map Name.fromLocal argNames) (Expr.generate mode body))
111 Opt.Ctor name index arity ->
112 let (args, ctor) = Expr.generateCtor mode name index arity in
114 var global (Expr.generateFunction args ctor)
117 Opt.Link linkedGlobal ->
118 addGlobal mode graph state linkedGlobal
120 Opt.Cycle cycle deps ->
121 addStmt (addDeps deps state) (
122 generateCycle mode global cycle
125 Opt.Manager effectsType ->
126 generateManager mode graph global effectsType state
128 Opt.Kernel clientChunks clientDeps maybeServer ->
130 Just (serverChunks, serverDeps) | Name.isServer mode ->
131 addBuilder (addDeps serverDeps state) (generateKernel mode serverChunks)
134 addBuilder (addDeps clientDeps state) (generateKernel mode clientChunks)
136 Opt.PortIncoming decoder deps ->
137 addStmt (addDeps deps state) (
138 generatePort mode global "incomingPort" decoder
141 Opt.PortOutgoing encoder deps ->
142 addStmt (addDeps deps state) (
143 generatePort mode global "outgoingPort" encoder
147addStmt :: State -> JS.Stmt -> State
149 addBuilder state (JS.stmtToBuilder stmt)
152addBuilder :: State -> B.Builder -> State
153addBuilder (State revBuilders seen) builder =
154 State (builder:revBuilders) seen
157var :: Opt.Global -> Expr.Code -> JS.Stmt
158var (Opt.Global home name) code =
159 JS.Var [ (Name.fromGlobal home name, Just (Expr.codeToExpr code)) ]
166generateCycle :: Mode -> Opt.Global -> [(N.Name, Opt.Expr)] -> JS.Stmt
167generateCycle mode (Opt.Global home _) cycle =
169 safeDefs = map (generateSafeCycle mode home) cycle
170 realDefs = map (generateRealCycle home) cycle
171 -- TODO add `try` in debug mode nice infinite recursion reports
173 JS.Block (safeDefs ++ realDefs)
176generateSafeCycle :: Mode -> ModuleName.Canonical -> (N.Name, Opt.Expr) -> JS.Stmt
177generateSafeCycle mode home (name, expr) =
178 JS.FunctionStmt (Name.fromCycle home name) [] $
179 Expr.codeToStmtList (Expr.generate mode expr)
182generateRealCycle :: ModuleName.Canonical -> (N.Name, expr) -> JS.Stmt
183generateRealCycle home (name, _) =
185 safeName = Name.fromCycle home name
186 realName = Name.fromGlobal home name
189 [ JS.Var [ ( realName, Just (JS.Call (JS.Ref safeName) []) ) ]
190 , JS.ExprStmt $ JS.Assign (JS.LRef safeName) $
191 JS.Function Nothing [] [ JS.Return (Just (JS.Ref realName)) ]
199generateKernel :: Mode -> [Opt.KChunk] -> B.Builder
200generateKernel mode chunks =
201 List.foldl' (addChunk mode) mempty chunks
204addChunk :: Mode -> B.Builder -> Opt.KChunk -> B.Builder
205addChunk mode builder chunk =
208 B.byteString javascript <> builder
211 Name.toBuilder (Name.fromGlobal (ModuleName.Canonical Pkg.core home) name) <> builder
214 Name.toBuilder (Name.fromField mode name) <> builder
217 Name.toBuilder (Name.fromInt int) <> builder
220 Name.toBuilder (Name.fromInt int) <> builder
243generatePort :: Mode -> Opt.Global -> N.Name -> Opt.Expr -> JS.Stmt
244generatePort mode (Opt.Global home name) makePort converter =
247 JS.Call (JS.Ref (Name.fromKernel N.platform makePort))
248 [ JS.String (N.toBuilder name)
249 , Expr.codeToExpr (Expr.generate mode converter)
252 JS.Var [ (Name.fromGlobal home name, Just definition) ]
260generateManager :: Mode -> Graph -> Opt.Global -> Opt.EffectsType -> State -> State
261generateManager mode graph (Opt.Global home@(ModuleName.Canonical _ moduleName) _) effectsType state =
265 (JS.Ref (Name.fromKernel N.platform "effectManagers"))
266 (JS.String (N.toBuilder moduleName))
268 (deps, args, stmts) =
269 generateManagerHelp home effectsType
272 JS.ExprStmt $ JS.Assign managerLVar $
273 JS.Call (JS.Ref (Name.fromKernel N.platform "createManager")) args
275 addStmt (List.foldl' (addGlobal mode graph) state deps) $
276 JS.Block (createManager : stmts)
279generateLeaf :: ModuleName.Canonical -> N.Name -> JS.Stmt
280generateLeaf home@(ModuleName.Canonical _ moduleName) name =
283 JS.Call leaf [ JS.String (N.toBuilder moduleName) ]
285 JS.Var [ (Name.fromGlobal home name, Just definition) ]
291 JS.Ref (Name.fromKernel N.platform "leaf")
294generateManagerHelp :: ModuleName.Canonical -> Opt.EffectsType -> ([Opt.Global], [JS.Expr], [JS.Stmt])
295generateManagerHelp home effectsType =
297 dep name = Opt.Global home name
298 ref name = JS.Ref (Name.fromGlobal home name)
302 ( [ dep "init", dep "onEffects", dep "onSelfMsg", dep "cmdMap" ]
303 , [ ref "init", ref "onEffects", ref "onSelfMsg", ref "cmdMap" ]
304 , [ generateLeaf home "command" ]
308 ( [ dep "init", dep "onEffects", dep "onSelfMsg", dep "subMap" ]
309 , [ ref "init", ref "onEffects", ref "onSelfMsg", JS.Int 0, ref "subMap" ]
310 , [ generateLeaf home "subscription" ]
314 ( [ dep "init", dep "onEffects", dep "onSelfMsg", dep "cmdMap", dep "subMap" ]
315 , [ ref "init", ref "onEffects", ref "onSelfMsg", ref "cmdMap", ref "subMap" ]
316 , [ generateLeaf home "command"
317 , generateLeaf home "subscription"
327 Map.Map ModuleName.Canonical Opt.Main
330generateMain :: Mode -> Graph -> Mains -> B.Builder
331generateMain mode graph mains =
333 [ stateToBuilder $ Map.foldrWithKey (addMain mode graph) emptyState mains
338addMain :: Mode -> Graph -> ModuleName.Canonical -> main -> State -> State
339addMain mode graph home _ state =
340 addGlobal mode graph state (Opt.Global home "main")
343exportMains :: Mains -> B.Builder
348verifyMains :: Mains -> [ModuleName.Canonical] -> Either [ModuleName.Canonical] Mains
349verifyMains mains modules =
351 rootSet = Set.fromList modules
352 rootMap = Map.restrictKeys mains rootSet
354 if Map.size rootMap == Set.size rootSet then
358 Set.intersection rootSet (Map.keysSet mains)
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