@@ -1,9 +1,12 @@
11{-# OPTIONS_GHC -Wall #-}
22{-# LANGUAGE OverloadedStrings #-}
33module Generate.JavaScript
4− ( Mode(..)
5− , Roots(..)
6− , generate
4+ ( ReplBuilder(..)
5+ , generateForRepl
6+ , Mode(..)
7+ , MainsBuilder(..)
8+ , MainTrie(..)
9+ , generateMains
710 )
811 where
912
@@ -15,9 +18,11 @@ import qualified Data.List as List
1518import Data.Map ((!))
1619import qualified Data.Map as Map
1720import qualified Data.Set as Set
21+import qualified Data.Text as Text
1822
1923import qualified AST.Optimized as Opt
2024import qualified AST.Module.Name as ModuleName
25+import qualified Elm.Interface as I
2126import qualified Elm.Name as N
2227import qualified Generate.JavaScript.Builder as JS
2328import qualified Generate.JavaScript.Expression as Expr
@@ -25,27 +30,62 @@ import qualified Generate.JavaScript.Name as Name
2530
2631
2732
28−-- GENERATE
33+-- GENERATE FOR REPL
34+
35+
36+data ReplBuilder =
37+ ReplBuilder
38+ { _repl_code :: B.Builder
39+ , _repl_name :: B.Builder
40+ }
41+
42+
43+generateForRepl :: Opt.Graph -> ModuleName.Canonical -> N.Name -> ReplBuilder
44+generateForRepl (Opt.Graph _ graph _) home name =
45+ ReplBuilder
46+ { _repl_code =
47+ stateToBuilder $
48+ addGlobal (Name.Debug Name.Client) graph emptyState (Opt.Global home name)
49+ , _repl_name =
50+ Name.toBuilder (Name.fromGlobal home name)
51+ }
52+
53+
54+
55+-- GENERATE MAINS
56+
57+
58+data MainsBuilder =
59+ MainsBuilder
60+ { _main_code :: B.Builder
61+ , _main_trie :: MainTrie
62+ }
2963
3064
3165data Mode = Debug | Prod
3266
3367
34−data Roots
35− = Mains [ModuleName.Canonical]
36− | Value ModuleName.Canonical N.Name
68+generateMains :: Mode -> Name.Target -> Opt.Graph -> I.Interfaces -> [ModuleName.Canonical] -> Either [ModuleName.Canonical] MainsBuilder
69+generateMains mode target (Opt.Graph mains graph fields) interfaces roots =
70+ let
71+ rootSet = Set.fromList roots
72+ rootMap = Map.restrictKeys mains rootSet
73+ in
74+ if Map.size rootMap == Set.size rootSet then
75+ let
76+ realMode = toRealMode mode target fields
77+ state = Map.foldrWithKey (addMain realMode graph) emptyState rootMap
78+ in
79+ Right $ MainsBuilder (stateToBuilder state) (toMainTrie realMode interfaces rootMap)
3780
81+ else
82+ Left $ Set.toList $
83+ Set.intersection rootSet (Map.keysSet mains)
3884
39−generate :: Mode -> Name.Target -> Opt.Graph -> Roots -> Either [ModuleName.Canonical] B.Builder
40−generate mode target (Opt.Graph mains nodes fields) roots =
41− case roots of
42− Value home name ->
43− Right $ stateToBuilder $
44− addGlobal (toRealMode mode target fields) nodes emptyState (Opt.Global home name)
4585
46− Mains modules ->
47− generateMain (toRealMode mode target fields) nodes
48− <$> verifyMains mains modules
86+addMain :: Name.Mode -> Graph -> ModuleName.Canonical -> main -> State -> State
87+addMain mode graph home _ state =
88+ addGlobal mode graph state (Opt.Global home "main")
4989
5090
5191toRealMode :: Mode -> Name.Target -> Map.Map N.Name Int -> Name.Mode
@@ -327,39 +367,61 @@ generateManagerHelp home effectsType =
327367
328368
329369
330−-- ADD MAIN
370+-- MAIN TRIE
331371
332372
333−type Mains =
334− Map.Map ModuleName.Canonical Opt.Main
335−
373+data MainTrie =
374+ MainTrie
375+ { _main :: Maybe B.Builder
376+ , _subs :: Map.Map N.Name MainTrie
377+ }
336378
337−generateMain :: Name.Mode -> Graph -> Mains -> B.Builder
338−generateMain mode graph mains =
339− mconcat
340− [ stateToBuilder $ Map.foldrWithKey (addMain mode graph) emptyState mains
341− , exportMains mains
342− ]
343379
380+emptyTrie :: MainTrie
381+emptyTrie =
382+ MainTrie Nothing Map.empty
344383
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")
348384
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
349388
350−exportMains :: Mains -> B.Builder
351−exportMains mains =
352− error "TODO" mains
353389
354−
355−verifyMains :: Mains -> [ModuleName.Canonical] -> Either [ModuleName.Canonical] Mains
356−verifyMains mains modules =
390+addMainTrie :: Name.Mode -> I.Interfaces -> ModuleName.Canonical -> Opt.Main -> MainTrie -> MainTrie
391+addMainTrie mode interfaces home@(ModuleName.Canonical _ moduleName) main trie =
357392 let
358− rootSet = Set.fromList modules
359− rootMap = Map.restrictKeys mains rootSet
393+ segments = Text.splitOn "." moduleName
394+ initMain = Expr.generateMain mode interfaces home segments main
395+ newTrie = segmentsToTrie segments (JS.exprToBuilder initMain)
360396 in
361− if Map.size rootMap == Set.size rootSet then
362− Right rootMap
363− else
364− Left $ Set.toList $
365− Set.intersection rootSet (Map.keysSet mains)
397+ merge trie newTrie
398+
399+
400+segmentsToTrie :: [N.Name] -> B.Builder -> MainTrie
401+segmentsToTrie segments mainBuilder =
402+ case segments of
403+ [] ->
404+ MainTrie (Just mainBuilder) Map.empty
405+
406+ segment : otherSegments ->
407+ MainTrie Nothing (Map.singleton segment (segmentsToTrie otherSegments mainBuilder))
408+
409+
410+merge :: MainTrie -> MainTrie -> MainTrie
411+merge (MainTrie main1 subs1) (MainTrie main2 subs2) =
412+ MainTrie
413+ (checkedMerge main1 main2)
414+ (Map.unionWith merge subs1 subs2)
415+
416+
417+checkedMerge :: Maybe a -> Maybe a -> Maybe a
418+checkedMerge a b =
419+ case (a, b) of
420+ (Nothing, main) ->
421+ main
422+
423+ (main, Nothing) ->
424+ main
425+
426+ (Just _, Just _) ->
427+ error "cannot have two modules with the same name"