@@ -1,9 +1,9 @@
11{-# OPTIONS_GHC -Wall #-}
22module Validate (declarations) where
33
4+import qualified Control.Arrow as Arrow
45import Control.Monad (foldM)
56import qualified Data.Map as Map
6−import qualified Data.Maybe as Maybe
77import qualified Data.Set as Set
88import qualified Data.Foldable as F
99import qualified Data.Traversable as T
@@ -12,6 +12,7 @@ import AST.Expression.General as Expr
1212import qualified AST.Expression.Source as Source
1313import qualified AST.Expression.Valid as Valid
1414import qualified AST.Declaration as D
15+import qualified AST.Module as Module
1516import qualified AST.Pattern as Pattern
1617import qualified AST.Type as Type
1718import Elm.Utils ((|>))
@@ -59,73 +60,148 @@ collapseComments listWithComments =
5960
6061
6162
62−-- EXTRACT DEFINES
63+-- PARTITION AND VALIDATE DEFINES
6364
6465
65−data StructuredSource =
66− Src
67− { _decls :: [Commented D.Source']
68− , _cmds :: Maybe [Commented Source.Effect]
69− , _subs :: Maybe [Commented Source.Effect]
70− }
66+type Defines =
67+ Map.Map D.EffectType [A.Located [D.CommentOr (A.Located Source.Effect)]]
7168
7269
73−extractEffects :: [Commented D.SourceOrDefine] -> Result.Result wrn Error.Error StructuredSource
74−extractEffects commentedDecls =
70+partitionEffects :: [Commented D.SourceOrDefine] -> ([Commented D.Source'], Defines)
71+partitionEffects commentedDecls =
7572 case commentedDecls of
7673 [] ->
77− Result.ok (Src [] Nothing Nothing)
74+ ([], Map.empty)
7875
7976 A.A ann (D.Source decl) : rest ->
80− do restSrc <- extractEffects rest
81− return $ restSrc { _decls = A.A ann decl : _decls restSrc }
77+ Arrow.first
78+ ((:) (A.A ann decl))
79+ (partitionEffects rest)
80+
81+ A.A (region, _) (D.Define effectType commentOrEffects) : rest ->
82+ Arrow.second
83+ (Map.insertWith (++) effectType [A.A region commentOrEffects])
84+ (partitionEffects rest)
85+
86+
87+validateDefines
88+ :: Module.Tag
89+ -> Defines
90+ -> Result.Result wrn Error.Error Valid.Effects
91+validateDefines tag defines =
92+ case tag of
93+ Module.None ->
94+ do disallowLeftoverDefines Error.BadDefineInNormalModule defines
95+ return Valid.None
96+
97+ Module.Effect region ->
98+ let
99+ (maybeCmds, smallerDefines) =
100+ extractKey D.Cmd defines
101+
102+ (maybeSubs, leftovers) =
103+ extractKey D.Sub smallerDefines
104+ in
105+ do disallowLeftoverDefines Error.BadDefineInEffectModule leftovers
106+ case (maybeCmds, maybeSubs) of
107+ (Nothing, Nothing) ->
108+ Result.throw region Error.NoDefineInEffectModule
109+
110+ _ ->
111+
112+ Valid.Effects
113+ <$> validateDefineDefs D.Cmd maybeCmds validateEffects
114+ <*> validateDefineDefs D.Sub maybeSubs validateEffects
115+
116+ Module.Foreign region ->
117+ let
118+ (maybeCmds, smallerDefines) =
119+ extractKey D.ForeignCmd defines
82120
83− A.A (region, _) (D.Define name commentOrEffects) : rest ->
84− do restSrc <- extractEffects rest
85− case name of
86− "commands" ->
87− case _cmds restSrc of
88− Nothing ->
89− do effects <- collapseComments commentOrEffects
90− Result.ok $ restSrc { _cmds = Just effects }
121+ (maybeSubs, leftovers) =
122+ extractKey D.ForeignSub smallerDefines
123+ in
124+ do disallowLeftoverDefines Error.BadDefineInForeignModule leftovers
125+ case (maybeCmds, maybeSubs) of
126+ (Nothing, Nothing) ->
127+ Result.throw region Error.NoDefineInForeignModule
128+
129+ (_, _) ->
130+ Valid.ForeignEffects
131+ <$> validateDefineDefs D.ForeignCmd maybeCmds (T.traverse validateForeignCmd)
132+ <*> validateDefineDefs D.ForeignSub maybeSubs (T.traverse validateForeignSub)
133+
134+
135+extractKey :: (Ord k) => k -> Map.Map k v -> (Maybe v, Map.Map k v)
136+extractKey key dict =
137+ ( Map.lookup key dict
138+ , Map.delete key dict
139+ )
140+
141+
142+validateDefineDefs
143+ :: D.EffectType
144+ -> Maybe [A.Located [D.CommentOr (A.Located Source.Effect)]]
145+ -> ([Commented Source.Effect] -> Result.Result wrn Error.Error a)
146+ -> Result.Result wrn Error.Error a
147+validateDefineDefs effectType maybeAllRawDefines validate =
148+ case maybeAllRawDefines of
149+ Nothing ->
150+ validate []
151+
152+ Just [A.A _ sourceDefs] ->
153+ validate =<< collapseComments sourceDefs
154+
155+ Just allRawDefines ->
156+ let
157+ (A.A region _) =
158+ last allRawDefines
91159
92− Just _ ->
93− Result.throw region (Error.DefineDuplicate name)
160+ errorMsg =
161+ Error.DuplicateDefines effectType (length allRawDefines)
162+ in
163+ Result.throw region errorMsg
94164
95− "subscriptions" ->
96− case _subs restSrc of
97− Nothing ->
98− do effects <- collapseComments commentOrEffects
99− Result.ok $ restSrc { _subs = Just effects }
100165
101− Just _ ->
102− Result.throw region (Error.DefineDuplicate name)
166+disallowLeftoverDefines
167+ :: (D.EffectType -> Error.Error)
168+ -> Defines
169+ -> Result.Result wrn Error.Error ()
170+disallowLeftoverDefines errorTagger leftoverDefines =
171+ case Map.toList leftoverDefines of
172+ [] ->
173+ Result.ok ()
103174
104− _ ->
105− Result.throw region (Error.DefineUnknown name)
175+ pairs ->
176+ let
177+ toErrors (key, allDefines) =
178+ map (A.map (\_ -> errorTagger key)) allDefines
179+ in
180+ Result.throwMany (concatMap toErrors pairs)
106181
107182
108183
109184-- VALIDATE STRUCTURED SOURCE
110185
111186
112−declarations :: [D.Source] -> Result.Result wrn Error.Error [D.Valid]
113−declarations sourceDecls =
114− do (Src decls cmds subs) <-
115− extractEffects =<< collapseComments sourceDecls
187+declarations
188+ :: Module.Tag
189+ -> [D.Source]
190+ -> Result.Result wrn Error.Error ([D.Valid], Valid.Effects)
191+declarations tag sourceDecls =
192+ do (decls, defines) <-
193+ partitionEffects <$> collapseComments sourceDecls
116194
117195 validDecls <-
118196 validateDecls decls
119197
120− validCmds <-
121− validateEffects (Maybe.fromMaybe [] cmds)
198+ validEffects <-
199+ validateDefines tag defines
122200
123− validSubs <-
124− validateEffects (Maybe.fromMaybe [] subs)
201+ F.traverse_ id
202+ (declDuplicates validDecls validEffects : map findBadTypeVars validDecls)
125203
126− (\_ _ -> validDecls)
127− <$> declDuplicates validDecls
128− <*> T.traverse checkDecl validDecls
204+ return (validDecls, validEffects)
129205
130206
131207
@@ -170,11 +246,11 @@ validateDeclsHelp
170246 -> Result.Result wrn Error.Error [D.Valid]
171247validateDeclsHelp maybeComment (A.A region def) decls =
172248 let
173− makeDef pat expr maybeType =
174− D.Def (Valid.Definition pat expr maybeType)
175−
176249 ann =
177250 (region, fmap A.drop maybeComment)
251+
252+ makeDef pat expr maybeType =
253+ D.Def (Valid.Definition pat expr maybeType)
178254 in
179255 case def of
180256 Source.Definition pat expr ->
@@ -203,21 +279,21 @@ validateDeclsHelp maybeComment (A.A region def) decls =
203279
204280validateEffects
205281 :: [Commented Source.Effect]
206− -> Result.Result wrn Error.Error [A.Commented Valid.Effect]
282+ -> Result.Result wrn Error.Error [A.Commented Valid.Def]
207283validateEffects effects =
208− case effects of
209− [] ->
210− Result.ok []
284+ case effects of
285+ [] ->
286+ Result.ok []
211287
212− A.A (region, maybeComment) effect : rest ->
213− validateEffectsHelp (region, fmap A.drop maybeComment) effect rest
288+ A.A (region, maybeComment) effect : rest ->
289+ validateEffectsHelp (region, fmap A.drop maybeComment) effect rest
214290
215291
216292validateEffectsHelp
217293 :: (R.Region, Maybe String)
218294 -> Source.Effect
219295 -> [Commented Source.Effect]
220− -> Result.Result wrn Error.Error [A.Commented Valid.Effect]
296+ -> Result.Result wrn Error.Error [A.Commented Valid.Def]
221297validateEffectsHelp ann effect remainingEffects =
222298 case effect of
223299 Source.With _ _ ->
@@ -225,7 +301,7 @@ validateEffectsHelp ann effect remainingEffects =
225301
226302 Source.Def pat expr ->
227303 (:)
228− <$> validateDef Valid.Def ann pat expr Nothing
304+ <$> validateDef Valid.Definition ann pat expr Nothing
229305 <*> validateEffects remainingEffects
230306
231307 Source.Type name tipe ->
@@ -236,13 +312,47 @@ validateEffectsHelp ann effect remainingEffects =
236312 A.A _ (Source.Def pat expr) : rest
237313 | Pattern.isVar name pat ->
238314 (:)
239− <$> validateDef Valid.Def ann pat expr (Just tipe)
315+ <$> validateDef Valid.Definition ann pat expr (Just tipe)
240316 <*> validateEffects rest
241317
242318 _ ->
243319 Result.throw (fst ann) (Error.TypeWithoutDefinition name)
244320
245321
322+validateForeignCmd
323+ :: Commented Source.Effect
324+ -> Result.Result wrn Error.Error (A.Commented Valid.ForeignCmd)
325+validateForeignCmd (A.A (region, maybeComment) effect) =
326+ case effect of
327+ Source.With _ _ ->
328+ Result.throw region (error "TODO")
329+
330+ Source.Def _ _ ->
331+ Result.throw region (error "TODO")
332+
333+ Source.Type name tipe ->
334+ Result.ok $
335+ A.A (region, fmap A.drop maybeComment) (Valid.Cmd name tipe)
336+
337+
338+validateForeignSub
339+ :: Commented Source.Effect
340+ -> Result.Result wrn Error.Error (A.Commented Valid.ForeignSub)
341+validateForeignSub (A.A (region, maybeComment) effect) =
342+ case effect of
343+ Source.With name expr ->
344+ do validExpr <- expression expr
345+ Result.ok $
346+ A.A (region, fmap A.drop maybeComment) (Valid.SubWith name validExpr)
347+
348+ Source.Def _ _ ->
349+ Result.throw region (error "TODO")
350+
351+ Source.Type name tipe ->
352+ Result.ok $
353+ A.A (region, fmap A.drop maybeComment) (Valid.Sub name tipe)
354+
355+
246356
247357-- VALIDATE DEFINITIONS
248358
@@ -398,8 +508,8 @@ second (value, expr) =
398508
399509
400510both
401− :: (Source.Expr, Source.Expr)
402− -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
511+ :: (Source.Expr, Source.Expr)
512+ -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
403513both (expr1, expr2) =
404514 (,) <$> expression expr1 <*> expression expr2
405515
@@ -446,13 +556,18 @@ defDuplicates patterns =
446556 |> detectDuplicates Error.DuplicateDefinition
447557
448558
449−declDuplicates :: [D.Valid] -> Result.Result wrn Error.Error ()
450−declDuplicates decls =
451− let (valueLists, typeLists) = unzip (map extractValues decls)
559+declDuplicates :: [D.Valid] -> Valid.Effects -> Result.Result wrn Error.Error ()
560+declDuplicates decls effects =
561+ let
562+ (valueLists, typeLists) =
563+ unzip (map extractValues decls)
564+
565+ effectValues =
566+ extractEffectValues effects
452567 in
453− (\_ _ -> ())
454− <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
455− <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
568+ (\_ _ -> ())
569+ <$> detectDuplicates Error.DuplicateValueDeclaration (effectValues ++ concat valueLists)
570+ <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
456571
457572
458573extractValues :: D.Valid -> ([A.Located String], [A.Located String])
@@ -484,12 +599,42 @@ extractValues (A.A (region, _) decl) =
484599 )
485600
486601
602+extractEffectValues :: Valid.Effects -> [A.Located String]
603+extractEffectValues effects =
604+ case effects of
605+ Valid.None ->
606+ []
607+
608+ Valid.Effects cmds subs ->
609+ let
610+ extractNames (Valid.Definition pat _ _) =
611+ Pattern.boundVars pat
612+ in
613+ concatMap (extractNames . A.drop) (cmds ++ subs)
614+
615+ Valid.ForeignEffects cmds subs ->
616+ let
617+ extractCmdNames (A.A (region, _) (Valid.Cmd name _)) =
618+ A.A region name
619+
620+ extractSubNames (A.A (region, _) sub) =
621+ A.A region $
622+ case sub of
623+ Valid.Sub name _ ->
624+ name
625+
626+ Valid.SubWith name _ ->
627+ name
628+ in
629+ map extractCmdNames cmds ++ map extractSubNames subs
630+
631+
487632
488633-- UNBOUND TYPE VARIABLES
489634
490635
491−checkDecl :: D.Valid -> Result.Result wrn Error.Error ()
492−checkDecl (A.A (region,_) decl) =
636+findBadTypeVars :: D.Valid -> Result.Result wrn Error.Error ()
637+findBadTypeVars (A.A (region,_) decl) =
493638 case decl of
494639 D.Def _ ->
495640 return ()