@@ -1,9 +1,12 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Generate.JavaScript
3module Generate.JavaScript
4− ( Mode(..)
6+ , Mode(..)
5− , Roots(..)
7+ , MainsBuilder(..)
6− , generate
8+ , MainTrie(..)
@@ -15,9 +18,11 @@ import qualified Data.List as List
15import Data.Map ((!))
18import Data.Map ((!))
16import qualified Data.Map as Map
19import qualified Data.Map as Map
17import qualified Data.Set as Set
20import qualified Data.Set as Set
21+import qualified Data.Text as Text
19import qualified AST.Optimized as Opt
23import qualified AST.Optimized as Opt
20import qualified AST.Module.Name as ModuleName
24import qualified AST.Module.Name as ModuleName
25+import qualified Elm.Interface as I
21import qualified Elm.Name as N
26import qualified Elm.Name as N
22import qualified Generate.JavaScript.Builder as JS
27import qualified Generate.JavaScript.Builder as JS
23import qualified Generate.JavaScript.Expression as Expr
28import qualified Generate.JavaScript.Expression as Expr
@@ -25,27 +30,62 @@ import qualified Generate.JavaScript.Name as Name
28−-- GENERATE
33+-- GENERATE FOR REPL
38+ { _repl_code :: B.Builder
39+ , _repl_name :: B.Builder
43+generateForRepl :: Opt.Graph -> ModuleName.Canonical -> N.Name -> ReplBuilder
44+generateForRepl (Opt.Graph _ graph _) home name =
48+ addGlobal (Name.Debug Name.Client) graph emptyState (Opt.Global home name)
50+ Name.toBuilder (Name.fromGlobal home name)
60+ { _main_code :: B.Builder
61+ , _main_trie :: MainTrie
31data Mode = Debug | Prod
65data Mode = Debug | Prod
34−data Roots
68+generateMains :: Mode -> Name.Target -> Opt.Graph -> I.Interfaces -> [ModuleName.Canonical] -> Either [ModuleName.Canonical] MainsBuilder
35− = Mains [ModuleName.Canonical]
69+generateMains mode target (Opt.Graph mains graph fields) interfaces roots =
36− | Value ModuleName.Canonical N.Name
70+ let
71+ rootSet = Set.fromList roots
72+ rootMap = Map.restrictKeys mains rootSet
74+ if Map.size rootMap == Set.size rootSet then
76+ realMode = toRealMode mode target fields
77+ state = Map.foldrWithKey (addMain realMode graph) emptyState rootMap
79+ Right $ MainsBuilder (stateToBuilder state) (toMainTrie realMode interfaces rootMap)
83+ Set.intersection rootSet (Map.keysSet mains)
39−generate :: Mode -> Name.Target -> Opt.Graph -> Roots -> Either [ModuleName.Canonical] B.Builder
40−generate mode target (Opt.Graph mains nodes fields) roots =
43− Right $ stateToBuilder $
44− addGlobal (toRealMode mode target fields) nodes emptyState (Opt.Global home name)
46− Mains modules ->
86+addMain :: Name.Mode -> Graph -> ModuleName.Canonical -> main -> State -> State
47− generateMain (toRealMode mode target fields) nodes
87+addMain mode graph home _ state =
48− <$> verifyMains mains modules
88+ addGlobal mode graph state (Opt.Global home "main")
51toRealMode :: Mode -> Name.Target -> Map.Map N.Name Int -> Name.Mode
91toRealMode :: Mode -> Name.Target -> Map.Map N.Name Int -> Name.Mode
@@ -327,39 +367,61 @@ generateManagerHelp home effectsType =
330−-- ADD MAIN
370+-- MAIN TRIE
333−type Mains =
373+data MainTrie =
334− Map.Map ModuleName.Canonical Opt.Main
374+ MainTrie
335−
375+ { _main :: Maybe B.Builder
376+ , _subs :: Map.Map N.Name MainTrie
337−generateMain :: Name.Mode -> Graph -> Mains -> B.Builder
338−generateMain mode graph mains =
340− [ stateToBuilder $ Map.foldrWithKey (addMain mode graph) emptyState mains
380+emptyTrie :: MainTrie
382+ MainTrie Nothing Map.empty
345−addMain :: Name.Mode -> Graph -> ModuleName.Canonical -> main -> State -> State
346−addMain mode graph home _ state =
347− addGlobal mode graph state (Opt.Global home "main")
385+toMainTrie :: Name.Mode -> I.Interfaces -> Map.Map ModuleName.Canonical Opt.Main -> MainTrie
386+toMainTrie mode interfaces mains =
387+ Map.foldrWithKey (addMainTrie mode interfaces) emptyTrie mains
350−exportMains :: Mains -> B.Builder
354−
390+addMainTrie :: Name.Mode -> I.Interfaces -> ModuleName.Canonical -> Opt.Main -> MainTrie -> MainTrie
355−verifyMains :: Mains -> [ModuleName.Canonical] -> Either [ModuleName.Canonical] Mains
391+addMainTrie mode interfaces home@(ModuleName.Canonical _ moduleName) main trie =
356−verifyMains mains modules =
358− rootSet = Set.fromList modules
393+ segments = Text.splitOn "." moduleName
359− rootMap = Map.restrictKeys mains rootSet
394+ initMain = Expr.generateMain mode interfaces home segments main
395+ newTrie = segmentsToTrie segments (JS.exprToBuilder initMain)
361− if Map.size rootMap == Set.size rootSet then
397+ merge trie newTrie
364− Left $ Set.toList $
400+segmentsToTrie :: [N.Name] -> B.Builder -> MainTrie
365− Set.intersection rootSet (Map.keysSet mains)
401+segmentsToTrie segments mainBuilder =
404+ MainTrie (Just mainBuilder) Map.empty
406+ segment : otherSegments ->
407+ MainTrie Nothing (Map.singleton segment (segmentsToTrie otherSegments mainBuilder))
410+merge :: MainTrie -> MainTrie -> MainTrie
411+merge (MainTrie main1 subs1) (MainTrie main2 subs2) =
413+ (checkedMerge main1 main2)
414+ (Map.unionWith merge subs1 subs2)
417+checkedMerge :: Maybe a -> Maybe a -> Maybe a
427+ error "cannot have two modules with the same name"