on master help sign in
Type check effect manager functions

Still more work to do on validation (make sure init, onEffects, and onSelfMsg all exist) and on error reporting though

commitfa09513527021478ec484b22b31ad9ef0f3e7cfb authorEvan Czaplicki <info@elm-lang.org> dateFri 4 Mar 2016, 16:45 (11 years ago) parent4b1ea5c
16 files changed+302−115
elm-compiler.cabal+2 src/AST/Effects.hs+27 src/AST/Expression/General.hs+2−14 src/AST/Module.hs+10−13 src/Canonicalize.hs+4 src/Canonicalize/Body.hs+33−25 src/Canonicalize/Environment.hs+1−2 src/Canonicalize/Setup.hs+15−9 src/Canonicalize/Sort.hs+3 src/Nitpick/PatternMatches.hs+3 src/Optimize.hs+3 src/Parse/Module.hs+11−6 src/Reporting/Error/Syntax.hs+4 src/Type/Constrain/Effects.hs+113 src/Type/Constrain/Expression.hs+5−5 src/Validate.hs+66−41
elm-compiler.cabal+2
@@ -48,6 +48,7 @@ Library
4848
4949 other-modules:
5050 AST.Declaration,
51+ AST.Effects,
5152 AST.Expression.Canonical,
5253 AST.Expression.General,
5354 AST.Expression.Optimized,
@@ -112,6 +113,7 @@ Library
112113 Reporting.Report,
113114 Reporting.Result,
114115 Reporting.Warning,
116+ Type.Constrain.Effects,
115117 Type.Constrain.Expression,
116118 Type.Constrain.Literal,
117119 Type.Constrain.Pattern,
src/AST/Effects.hsnew file+27
@@ -0,0 +1,27 @@
1+module AST.Effects where
2+
3+import qualified Reporting.Annotation as A
4+import qualified Reporting.Region as R
5+
6+
7+
8+data Effects
9+ = None
10+ | Effect Info
11+ | Foreign
12+
13+
14+data Info =
15+ Info
16+ { _tag :: R.Region
17+ , _init :: R.Region
18+ , _onEffects :: R.Region
19+ , _onSelfMsg :: R.Region
20+ , _type :: ManagerType
21+ }
22+
23+
24+data ManagerType
25+ = CmdManager (A.Located String)
26+ | SubManager (A.Located String)
27+ | FxManager (A.Located String) (A.Located String)
src/AST/Expression/General.hs+2−14
@@ -8,6 +8,7 @@ enrich the AST with more information.
88-}
99module AST.Expression.General where
1010
11+import qualified AST.Effects as Fx
1112import qualified AST.Literal as Literal
1213import qualified AST.Module.Name as ModuleName
1314import qualified AST.Pattern as Pattern
@@ -56,6 +57,7 @@ data Expr' ann def var typ
5657 -- for type checking and code gen only
5758 | Cmd ModuleName.Canonical String
5859 | Sub ModuleName.Canonical String
60+ | SaveEnv ModuleName.Canonical Fx.Effects
5961 | GLShader String String Literal.GLShaderTipe
6062
6163
@@ -78,20 +80,6 @@ tuple expressions =
7880 Data ("_Tuple" ++ show (length expressions)) expressions
7981
8082
81−saveEnvName :: String
82−saveEnvName =
83− "_save_the_environment!!!"
84−
85−
86−dummyLet :: [def] -> Expr ann def Var.Canonical typ
87−dummyLet defs =
88− let
89− body =
90− A.A undefined (Var (Var.builtin saveEnvName))
91− in
92− A.A undefined (Let defs body)
93−
94−
9583collectApps :: Expr ann def var typ -> [Expr ann def var typ]
9684collectApps annExpr@(A.A _ expr) =
9785 case expr of
src/AST/Module.hs+10−13
@@ -2,7 +2,7 @@ module AST.Module
22 ( Header(..), Module(..)
33
44 , Source, SourceInfo(..), SourceTag(..), SourceSettings, emptySettings
5− , Valid, ValidInfo(..), ValidEffects(..)
5+ , Valid, ValidInfo(..)
66 , Canonical, Optimized, Info(..)
77
88 , UserImport, DefaultImport, ImportMethod(..)
@@ -19,6 +19,7 @@ import Data.Binary
1919import qualified Data.Map as Map
2020
2121import qualified AST.Declaration as Decl
22+import qualified AST.Effects as Fx
2223import qualified AST.Expression.Canonical as Canonical
2324import qualified AST.Expression.Optimized as Optimized
2425import qualified AST.Module.Name as Name
@@ -28,6 +29,7 @@ import qualified Docs.AST as Docs
2829import qualified Elm.Package as Package
2930import qualified Elm.Compiler.Version as Compiler
3031import qualified Reporting.Annotation as A
32+import qualified Reporting.Region as R
3133
3234
3335
@@ -74,9 +76,9 @@ data SourceInfo =
7476
7577
7678data SourceTag
77− = SrcNormal
78− | SrcEffect
79− | SrcForeign
79+ = Normal
80+ | Effect R.Region
81+ | Foreign R.Region
8082
8183
8284type SourceSettings =
@@ -98,16 +100,10 @@ data ValidInfo =
98100 , validExports :: Var.Listing (A.Located Var.Value)
99101 , validImports :: ([DefaultImport], [UserImport])
100102 , validDecls :: [Decl.Valid]
101− , validEffects :: ValidEffects
103+ , validEffects :: Fx.Effects
102104 }
103105
104106
105−data ValidEffects
106− = ValidNormal
107− | ValidEffect (Maybe (A.Located String)) (Maybe (A.Located String))
108− | ValidForeign
109−
110−
111107type Canonical =
112108 Module (Info Canonical.Expr)
113109
@@ -137,16 +133,17 @@ data ImportMethod =
137133-- LATE PHASE MODULE INFORMATION
138134
139135
140−data Info expr =
136+data Info program =
141137 Info
142138 { docs :: A.Located (Maybe Docs.Centralized)
143139 , exports :: [Var.Value]
144140 , imports :: [Name.Raw]
145− , program :: expr
141+ , program :: program
146142 , types :: Types
147143 , fixities :: [(Decl.Assoc, Int, String)]
148144 , aliases :: Aliases
149145 , unions :: Unions
146+ , effects :: Fx.Effects
150147 }
151148
152149
src/Canonicalize.hs+4
@@ -99,6 +99,7 @@ module' canonicalImports interfaces modul =
9999 , Module.fixities = fixities
100100 , Module.aliases = aliases
101101 , Module.unions = unions
102+ , Module.effects = effects
102103 }
103104 }
104105
@@ -440,6 +441,9 @@ expression env (A.A region validExpr) =
440441 Sub moduleName string ->
441442 Result.ok (Sub moduleName string)
442443
444+ SaveEnv moduleName effects ->
445+ Result.ok (SaveEnv moduleName effects)
446+
443447 GLShader uid src tipe ->
444448 Result.ok (GLShader uid src tipe)
445449
src/Canonicalize/Body.hs+33−25
@@ -2,9 +2,9 @@
22module Canonicalize.Body (flatten) where
33
44import qualified AST.Declaration as D
5+import qualified AST.Effects as Fx
56import qualified AST.Expression.General as E
67import qualified AST.Expression.Canonical as Canonical
7−import qualified AST.Module as Module
88import qualified AST.Module.Name as ModuleName
99import qualified AST.Pattern as P
1010import qualified AST.Type as T
@@ -15,7 +15,7 @@ import qualified Reporting.Region as R
1515
1616
1717
18−flatten :: ModuleName.Canonical -> [D.Canonical] -> Module.ValidEffects -> Canonical.Expr
18+flatten :: ModuleName.Canonical -> [D.Canonical] -> Fx.Effects -> Canonical.Expr
1919flatten moduleName decls effects =
2020 let
2121 declDefs =
@@ -23,8 +23,14 @@ flatten moduleName decls effects =
2323
2424 effectDefs =
2525 effectsToDefs moduleName effects
26+
27+ loc =
28+ A.A (error "this annotation should never be needed")
2629 in
27− Sort.definitions (E.dummyLet (declDefs ++ effectDefs))
30+ Sort.definitions $ loc $
31+ E.Let
32+ (declDefs ++ effectDefs)
33+ (loc $ E.SaveEnv moduleName effects)
2834
2935
3036
@@ -112,35 +118,37 @@ definition name expr@(A.A ann _) region tipe =
112118-- EFFECTS
113119
114120
115−effectsToDefs :: ModuleName.Canonical -> Module.ValidEffects -> [Canonical.Def]
121+effectsToDefs :: ModuleName.Canonical -> Fx.Effects -> [Canonical.Def]
116122effectsToDefs moduleName effects =
117123 case effects of
118− Module.ValidNormal ->
124+ Fx.None ->
119125 []
120126
121− Module.ValidEffect maybeCmd maybeSub ->
122− effectsToDefsHelp "command" (E.Cmd moduleName) maybeCmd
123− ++ effectsToDefsHelp "subscription" (E.Sub moduleName) maybeSub
124−
125− Module.ValidForeign ->
127+ Fx.Foreign ->
126128 []
127129
130+ Fx.Effect info ->
131+ case Fx._type info of
132+ Fx.CmdManager cmd ->
133+ [ effectsToDefsHelp "command" (E.Cmd moduleName) cmd ]
134+
135+ Fx.SubManager sub ->
136+ [ effectsToDefsHelp "subscription" (E.Sub moduleName) sub ]
137+
138+ Fx.FxManager cmd sub ->
139+ [ effectsToDefsHelp "command" (E.Cmd moduleName) cmd
140+ , effectsToDefsHelp "subscription" (E.Sub moduleName) sub
141+ ]
142+
128143
129144effectsToDefsHelp
130145 :: String
131146 -> (String -> Canonical.Expr')
132− -> Maybe (A.Located String)
133− -> [Canonical.Def]
134−effectsToDefsHelp name toExpr' maybeEffect =
135− case maybeEffect of
136− Nothing ->
137− []
138−
139− Just (A.A region typeName) ->
140− [ Canonical.Definition
141− Canonical.dummyFacts
142− (A.A region (P.Var name))
143− (A.A region (toExpr' typeName))
144− Nothing
145− ]
146−
147+ -> A.Located String
148+ -> Canonical.Def
149+effectsToDefsHelp name toExpr' (A.A region typeName) =
150+ Canonical.Definition
151+ Canonical.dummyFacts
152+ (A.A region (P.Var name))
153+ (A.A region (toExpr' typeName))
154+ Nothing
src/Canonicalize/Environment.hs+1−2
@@ -13,7 +13,6 @@ import qualified Data.Map as Map
1313import qualified Data.Maybe as Maybe
1414import qualified Data.Set as Set
1515
16−import AST.Expression.General (saveEnvName)
1716import qualified AST.Module.Name as ModuleName
1817import qualified AST.Pattern as P
1918import qualified AST.Type as Type
@@ -112,7 +111,7 @@ insert key value =
112111builtinPatches :: [Patch]
113112builtinPatches =
114113 concat
115− [ map (patch Value) (tupleNames ++ [saveEnvName])
114+ [ map (patch Value) tupleNames
116115 , map (patch Union) (tupleNames ++ ["List","Int","Float","Char","Bool","String"])
117116 , map (patternPatch) (tuples ++ [ ("::", 2), ("[]", 0) ])
118117 ]
src/Canonicalize/Setup.hs+15−9
@@ -8,6 +8,7 @@ import qualified Data.Maybe as Maybe
88import qualified Data.Traversable as Trav
99
1010import qualified AST.Declaration as D
11+import qualified AST.Effects as Fx
1112import qualified AST.Expression.Valid as Valid
1213import qualified AST.Module as Module
1314import qualified AST.Module.Name as ModuleName
@@ -367,21 +368,26 @@ declToPatches moduleName (A.A (region,_) decl) =
367368-- EFFECTS TO PATCHES
368369
369370
370−effectsToPatches :: ModuleName.Canonical -> Module.ValidEffects -> [Env.Patch]
371+effectsToPatches :: ModuleName.Canonical -> Fx.Effects -> [Env.Patch]
371372effectsToPatches moduleName effects =
372373 case effects of
373− Module.ValidNormal ->
374+ Fx.None ->
374375 []
375376
376− Module.ValidEffect maybeCmd maybeSub ->
377+ Fx.Foreign ->
378+ []
379+
380+ Fx.Effect info ->
377381 map (\name -> Env.Value name (Var.topLevel moduleName name)) $
378− Maybe.catMaybes
379− [ fmap (const "command") maybeCmd
380− , fmap (const "subscription") maybeSub
381− ]
382+ case Fx._type info of
383+ Fx.CmdManager _ ->
384+ [ "command" ]
382385
383− Module.ValidForeign ->
384− []
386+ Fx.SubManager _ ->
387+ [ "subscription" ]
388+
389+ Fx.FxManager _ _ ->
390+ [ "command", "subscription" ]
385391
386392
387393
src/Canonicalize/Sort.hs+3
@@ -102,6 +102,9 @@ reorder (A.A ann expression) =
102102 Sub _ _ ->
103103 return expression
104104
105+ SaveEnv _ _ ->
106+ return expression
107+
105108 GLShader _ _ _ ->
106109 return expression
107110
src/Nitpick/PatternMatches.hs+3
@@ -189,6 +189,9 @@ checkExpression tagDict (A.A region expression) =
189189 E.Sub _ _ ->
190190 Result.ok ()
191191
192+ E.SaveEnv _ _ ->
193+ Result.ok ()
194+
192195 E.GLShader _ _ _ ->
193196 Result.ok ()
194197
src/Optimize.hs+3
@@ -307,6 +307,9 @@ optimizeExpr context annExpr@(A.A region expression) =
307307 Expr.Sub moduleName _ ->
308308 pure (Opt.Sub moduleName)
309309
310+ Expr.SaveEnv _ _ ->
311+ error "save_the_environment should never make it to optimization phase"
312+
310313 Expr.GLShader uid src gltipe ->
311314 pure (Opt.GLShader uid src gltipe)
312315
src/Parse/Module.hs+11−6
@@ -8,6 +8,7 @@ import qualified AST.Module as Module
88import qualified AST.Module.Name as ModuleName
99import qualified AST.Variable as Var
1010import qualified Reporting.Annotation as A
11+import qualified Reporting.Region as R
1112
1213
1314getModuleName :: String -> Maybe String
@@ -31,7 +32,7 @@ header =
3132 do optional freshLine
3233 (ModuleDecl tag names exports settings) <-
3334 option
34− (ModuleDecl Module.SrcNormal ["Main"] Var.openListing Module.emptySettings)
35+ (ModuleDecl Module.Normal ["Main"] Var.openListing Module.emptySettings)
3536 (moduleDecl `followedBy` freshLine)
3637
3738 docs <-
@@ -76,19 +77,23 @@ parseTag =
7677 choice
7778 [
7879 do try (reserved "module")
79− return Module.SrcNormal
80+ return Module.Normal
8081 ,
81− do try (reserved "effect")
82+ do start <- getMyPosition
83+ try (reserved "effect")
8284 whitespace
8385 reserved "module"
84− return Module.SrcEffect
86+ end <- getMyPosition
87+ return (Module.Effect (R.Region start end))
8588 ,
86− do reserved "foreign"
89+ do start <- getMyPosition
90+ reserved "foreign"
8791 whitespace
8892 reserved "effect"
8993 whitespace
9094 reserved "module"
91− return Module.SrcForeign
95+ end <- getMyPosition
96+ return (Module.Foreign (R.Region start end))
9297 ]
9398
9499
src/Reporting/Error/Syntax.hs+4
@@ -24,6 +24,7 @@ data Error
2424 | SettingsOnForeignModule
2525 | DuplicateSettingOnEffectModule String
2626 | BadSettingOnEffectModule String
27+ | NoSettingsOnEffectModule
2728
2829 | InfixDuplicate String
2930 | TypeWithoutDefinition String
@@ -120,6 +121,9 @@ toReport _localizer err =
120121 BadSettingOnEffectModule name ->
121122 error "TODO - BadSettingOnEffectModule" name
122123
124+ NoSettingsOnEffectModule ->
125+ error "TODO - NoSettingsOnEffectModule"
126+
123127 InfixDuplicate opName ->
124128 Report.report
125129 "INFIX OVERLAP"
src/Type/Constrain/Effects.hsnew file+113
@@ -0,0 +1,113 @@
1+{-# OPTIONS_GHC -Wall #-}
2+module Type.Constrain.Effects (constrain) where
3+
4+import qualified Data.Map as Map
5+
6+import qualified AST.Effects as Fx
7+import qualified AST.Module.Name as ModuleName
8+import qualified Reporting.Annotation as A
9+import qualified Type.Environment as Env
10+import Type.Type
11+ ( Variable, Type, TypeConstraint, Constraint(..), Scheme(Scheme)
12+ , TermN(VarN), (==>), (<|), mkVar
13+ )
14+
15+
16+constrain
17+ :: Env.Environment
18+ -> ModuleName.Canonical
19+ -> Fx.Effects
20+ -> IO TypeConstraint
21+constrain env moduleName effects =
22+ case effects of
23+ Fx.None ->
24+ return CSaveEnv
25+
26+ Fx.Foreign ->
27+ return CSaveEnv
28+
29+ Fx.Effect info ->
30+ constrainHelp env moduleName info
31+
32+
33+constrainHelp
34+ :: Env.Environment
35+ -> ModuleName.Canonical
36+ -> Fx.Info
37+ -> IO TypeConstraint
38+constrainHelp env moduleName (Fx.Info tagRegion r0 r1 r2 managerType) =
39+ let
40+ task t =
41+ Env.getType env "Platform.Task" <| Env.getType env "Basics.Never" <| VarN t
42+
43+ router msg selfMsg =
44+ Env.getType env "Platform.Router" <| VarN msg <| VarN selfMsg
45+ in
46+ do v0 <- mkVar Nothing
47+ v1 <- mkVar Nothing
48+ v2 <- mkVar Nothing
49+
50+ state0 <- mkVar Nothing
51+ state1 <- mkVar Nothing
52+ state2 <- mkVar Nothing
53+
54+ msg1 <- mkVar Nothing
55+ msg2 <- mkVar Nothing
56+
57+ selfMsg1 <- mkVar Nothing
58+ selfMsg2 <- mkVar Nothing
59+
60+ let
61+ vars =
62+ [v0, v1, v2, state0, state1, state2, msg1, msg2, selfMsg1, selfMsg2]
63+
64+ onEffectsType =
65+ router msg1 selfMsg1
66+ ==> addEffectArgs env moduleName managerType msg1
67+ (VarN state1 ==> task state1)
68+
69+ onSelfMsgType =
70+ router msg2 selfMsg2 ==> VarN selfMsg2 ==> VarN state2 ==> task state2
71+
72+ constrains =
73+ [ CInstance tagRegion "init" (VarN v0)
74+ , CInstance tagRegion "onEffects" (VarN v1)
75+ , CInstance tagRegion "onSelfMsg" (VarN v2)
76+ , CEqual (error "TODO 1") r0 (VarN v0) (task state0)
77+ , CEqual (error "TODO 2") r1 (VarN v1) onEffectsType
78+ , CEqual (error "TODO 3") r2 (VarN v2) onSelfMsgType
79+ , CEqual (error "TODO 4") r1 (VarN state0) (VarN state1)
80+ , CEqual (error "TODO 5") r2 (VarN state0) (VarN state2)
81+ , CEqual (error "TODO 6") r2 (VarN selfMsg1) (VarN selfMsg2)
82+ ]
83+
84+ return $
85+ CLet [Scheme [] vars (CAnd constrains) Map.empty] CSaveEnv
86+
87+
88+addEffectArgs
89+ :: Env.Environment
90+ -> ModuleName.Canonical
91+ -> Fx.ManagerType
92+ -> Variable
93+ -> Type
94+ -> Type
95+addEffectArgs env moduleName managerType msg result =
96+ let
97+ toTypeName (A.A _ name) =
98+ ModuleName.canonicalToString moduleName ++ "." ++ name
99+
100+ effectList fxName =
101+ Env.getType env "List" <|
102+ (Env.getType env (toTypeName fxName) <| VarN msg)
103+ in
104+ case managerType of
105+ Fx.CmdManager cmd ->
106+ effectList cmd ==> result
107+
108+ Fx.SubManager sub ->
109+ effectList sub ==> result
110+
111+ Fx.FxManager cmd sub ->
112+ effectList cmd ==> effectList sub ==> result
113+
src/Type/Constrain/Expression.hs+5−5
@@ -14,6 +14,7 @@ import qualified AST.Variable as V
1414import qualified Reporting.Annotation as A
1515import qualified Reporting.Error.Type as Error
1616import qualified Reporting.Region as R
17+import qualified Type.Constrain.Effects as Effects
1718import qualified Type.Constrain.Literal as Literal
1819import qualified Type.Constrain.Pattern as Pattern
1920import qualified Type.Environment as Env
@@ -46,6 +47,9 @@ constrain env annotatedExpr@(A.A region expression) tipe =
4647 Env.instantiateType env (ST.sub moduleName typeName) Map.empty
4748 return $ ex vars (CEqual (error "TODO - Sub") region sub tipe)
4849
50+ E.SaveEnv moduleName effects ->
51+ Effects.constrain env moduleName effects
52+
4953 E.GLShader _uid _src gltipe ->
5054 exists $ \attr ->
5155 exists $ \unif ->
@@ -71,11 +75,7 @@ constrain env annotatedExpr@(A.A region expression) tipe =
7175 return (CEqual Error.Shader region (shaderTipe attribute uniform varying) tipe)
7276
7377 E.Var var ->
74− let
75− name =
76− V.toString var
77− in
78− return (if name == E.saveEnvName then CSaveEnv else CInstance region name tipe)
78+ return (CInstance region (V.toString var) tipe)
7979
8080 E.Range lowExpr highExpr ->
8181 existsNumber $ \n ->
src/Validate.hs+66−41
@@ -1,13 +1,14 @@
11{-# OPTIONS_GHC -Wall #-}
22module Validate (module') where
33
4−import Control.Monad (foldM)
4+import Control.Monad (foldM, when)
55import qualified Data.Map as Map
66import qualified Data.Set as Set
77import qualified Data.Foldable as F
88import qualified Data.Traversable as T
99
1010import AST.Expression.General as Expr
11+import qualified AST.Effects as Fx
1112import qualified AST.Expression.Source as Source
1213import qualified AST.Expression.Valid as Valid
1314import qualified AST.Declaration as D
@@ -61,19 +62,28 @@ addDefaults pkgName imports =
6162validateModuleDecl
6263 :: Module.SourceTag
6364 -> Module.SourceSettings
64− -> Result.Result wrn Error.Error Module.ValidEffects
65−validateModuleDecl tag settings =
65+ -> Result.Result wrn Error.Error Fx.Effects
66+validateModuleDecl tag settings@(A.A _ pairs) =
6667 case tag of
67− Module.SrcNormal ->
68+ Module.Normal ->
6869 do noSettings Error.SettingsOnNormalModule settings
69− return Module.ValidNormal
70+ return Fx.None
7071
71− Module.SrcForeign ->
72+ Module.Foreign _ ->
7273 do noSettings Error.SettingsOnForeignModule settings
73− return Module.ValidForeign
74+ return Fx.Foreign
7475
75− Module.SrcEffect ->
76− gatherEffectSettings settings
76+ Module.Effect tagRegion ->
77+ let
78+ collectSettings (A.A region setting, userValue) dict =
79+ Map.insertWith (++) setting [(region, userValue)] dict
80+
81+ settingsDict =
82+ foldr collectSettings Map.empty pairs
83+ in
84+ do managerType <- toManagerType tagRegion settingsDict
85+ return $ Fx.Effect $
86+ Fx.Info tagRegion (error "TODO") (error "TODO") (error "TODO") managerType
7787
7888
7989noSettings
@@ -89,47 +99,59 @@ noSettings errorMsg (A.A region settings) =
8999 Result.throw region errorMsg
90100
91101
92−gatherEffectSettings
93− :: Module.SourceSettings
94− -> Result.Result wrn Error.Error Module.ValidEffects
95−gatherEffectSettings (A.A _ pairs) =
96− uncurry Module.ValidEffect <$>
97− gatherEffectSettingsHelp (Nothing, Nothing) pairs
102+toManagerType
103+ :: R.Region
104+ -> Map.Map String [(R.Region, A.Located String)]
105+ -> Result.Result wrn Error.Error Fx.ManagerType
106+toManagerType tagRegion settingsDict =
107+ let
108+ toErrors name entries =
109+ map (\entry -> A.A (fst entry) (Error.BadSettingOnEffectModule name)) entries
110+
111+ errors =
112+ settingsDict
113+ |> Map.delete "command"
114+ |> Map.delete "subscription"
115+ |> Map.mapWithKey toErrors
116+ |> Map.elems
117+ |> concat
118+ in
119+ do when (not (null errors)) (Result.throwMany errors)
120+ maybeEffects <-
121+ (,) <$> extractOne "command" settingsDict
122+ <*> extractOne "subscription" settingsDict
98123
124+ case maybeEffects of
125+ (Nothing, Nothing) ->
126+ Result.throw tagRegion Error.NoSettingsOnEffectModule
99127
100−type Effects =
101− (Maybe (A.Located String), Maybe (A.Located String))
128+ (Just cmd, Nothing) ->
129+ return (Fx.CmdManager cmd)
102130
131+ (Nothing, Just sub) ->
132+ return (Fx.SubManager sub)
103133
104−gatherEffectSettingsHelp
105− :: Effects
106− -> [(A.Located String, A.Located String)]
107− -> Result.Result wrn Error.Error Effects
108−gatherEffectSettingsHelp effects@(maybeCmd, maybeSub) pairs =
109− case pairs of
110− [] ->
111− Result.ok effects
134+ (Just cmd, Just sub) ->
135+ return (Fx.FxManager cmd sub)
112136
113− (A.A region name, effect) : rest ->
114− case name of
115− "command" ->
116− case maybeCmd of
117− Nothing ->
118− gatherEffectSettingsHelp (Just effect, maybeSub) rest
119137
120− Just _ ->
121− Result.throw region (Error.DuplicateSettingOnEffectModule name)
138+extractOne
139+ :: String
140+ -> Map.Map String [(R.Region, A.Located String)]
141+ -> Result.Result w Error.Error (Maybe (A.Located String))
142+extractOne name settingsDict =
143+ case Map.lookup name settingsDict of
144+ Nothing ->
145+ return Nothing
122146
123− "subscription" ->
124− case maybeSub of
125− Nothing ->
126− gatherEffectSettingsHelp (maybeCmd, Just effect) rest
147+ Just [] ->
148+ error "Empty lists should never be added to the dictionary of effect module settings."
127149
128− Just _ ->
129− Result.throw region (Error.DuplicateSettingOnEffectModule name)
150+ Just [(_, userType)] ->
151+ return (Just userType)
130152
131− _ ->
132− Result.throw region (Error.BadSettingOnEffectModule name)
153+ Just ((region, _) : _) ->
154+ Result.throw region (Error.DuplicateSettingOnEffectModule name)
133155
134156
135157
@@ -407,6 +429,9 @@ expression (A.A ann sourceExpression) =
407429 Sub moduleName typeName ->
408430 return (Sub moduleName typeName)
409431
432+ SaveEnv moduleName effects ->
433+ return (SaveEnv moduleName effects)
434+
410435 GLShader uid src gltipe ->
411436 return (GLShader uid src gltipe)
412437