@@ -1,9 +1,9 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2module Validate (declarations) where
2module Validate (declarations) where
4+import qualified Control.Arrow as Arrow
4import Control.Monad (foldM)
5import Control.Monad (foldM)
5import qualified Data.Map as Map
6import qualified Data.Map as Map
6−import qualified Data.Maybe as Maybe
7import qualified Data.Set as Set
7import qualified Data.Set as Set
8import qualified Data.Foldable as F
8import qualified Data.Foldable as F
9import qualified Data.Traversable as T
9import qualified Data.Traversable as T
@@ -12,6 +12,7 @@ import AST.Expression.General as Expr
12import qualified AST.Expression.Source as Source
12import qualified AST.Expression.Source as Source
13import qualified AST.Expression.Valid as Valid
13import qualified AST.Expression.Valid as Valid
14import qualified AST.Declaration as D
14import qualified AST.Declaration as D
15+import qualified AST.Module as Module
15import qualified AST.Pattern as Pattern
16import qualified AST.Pattern as Pattern
16import qualified AST.Type as Type
17import qualified AST.Type as Type
17import Elm.Utils ((|>))
18import Elm.Utils ((|>))
@@ -59,73 +60,148 @@ collapseComments listWithComments =
62−-- EXTRACT DEFINES
63+-- PARTITION AND VALIDATE DEFINES
65−data StructuredSource =
66+type Defines =
66− Src
67+ Map.Map D.EffectType [A.Located [D.CommentOr (A.Located Source.Effect)]]
67− { _decls :: [Commented D.Source']
68− , _cmds :: Maybe [Commented Source.Effect]
69− , _subs :: Maybe [Commented Source.Effect]
73−extractEffects :: [Commented D.SourceOrDefine] -> Result.Result wrn Error.Error StructuredSource
70+partitionEffects :: [Commented D.SourceOrDefine] -> ([Commented D.Source'], Defines)
74−extractEffects commentedDecls =
71+partitionEffects commentedDecls =
75 case commentedDecls of
72 case commentedDecls of
77− Result.ok (Src [] Nothing Nothing)
74+ ([], Map.empty)
79 A.A ann (D.Source decl) : rest ->
76 A.A ann (D.Source decl) : rest ->
80− do restSrc <- extractEffects rest
77+ Arrow.first
81− return $ restSrc { _decls = A.A ann decl : _decls restSrc }
78+ ((:) (A.A ann decl))
79+ (partitionEffects rest)
81+ A.A (region, _) (D.Define effectType commentOrEffects) : rest ->
83+ (Map.insertWith (++) effectType [A.A region commentOrEffects])
84+ (partitionEffects rest)
90+ -> Result.Result wrn Error.Error Valid.Effects
91+validateDefines tag defines =
94+ do disallowLeftoverDefines Error.BadDefineInNormalModule defines
97+ Module.Effect region ->
99+ (maybeCmds, smallerDefines) =
100+ extractKey D.Cmd defines
102+ (maybeSubs, leftovers) =
103+ extractKey D.Sub smallerDefines
105+ do disallowLeftoverDefines Error.BadDefineInEffectModule leftovers
106+ case (maybeCmds, maybeSubs) of
107+ (Nothing, Nothing) ->
108+ Result.throw region Error.NoDefineInEffectModule
113+ <$> validateDefineDefs D.Cmd maybeCmds validateEffects
114+ <*> validateDefineDefs D.Sub maybeSubs validateEffects
116+ Module.Foreign region ->
118+ (maybeCmds, smallerDefines) =
119+ extractKey D.ForeignCmd defines
83− A.A (region, _) (D.Define name commentOrEffects) : rest ->
121+ (maybeSubs, leftovers) =
84− do restSrc <- extractEffects rest
122+ extractKey D.ForeignSub smallerDefines
86− "commands" ->
124+ do disallowLeftoverDefines Error.BadDefineInForeignModule leftovers
87− case _cmds restSrc of
125+ case (maybeCmds, maybeSubs) of
126+ (Nothing, Nothing) ->
127+ Result.throw region Error.NoDefineInForeignModule
130+ Valid.ForeignEffects
131+ <$> validateDefineDefs D.ForeignCmd maybeCmds (T.traverse validateForeignCmd)
132+ <*> validateDefineDefs D.ForeignSub maybeSubs (T.traverse validateForeignSub)
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
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
88− Nothing ->
149+ Nothing ->
152+ Just [A.A _ sourceDefs] ->
89− do effects <- collapseComments commentOrEffects
153+ validate =<< collapseComments sourceDefs
90− Result.ok $ restSrc { _cmds = Just effects }
154+
155+ Just allRawDefines ->
92− Just _ ->
160+ errorMsg =
161+ Error.DuplicateDefines effectType (length allRawDefines)
93− Result.throw region (Error.DefineDuplicate name)
163+ Result.throw region errorMsg
96− case _subs restSrc of
98− do effects <- collapseComments commentOrEffects
99− Result.ok $ restSrc { _subs = Just effects }
101− Just _ ->
166+disallowLeftoverDefines
102− Result.throw region (Error.DefineDuplicate name)
167+ :: (D.EffectType -> Error.Error)
169+ -> Result.Result wrn Error.Error ()
170+disallowLeftoverDefines errorTagger leftoverDefines =
171+ case Map.toList leftoverDefines of
105− Result.throw region (Error.DefineUnknown name)
176+ let
177+ toErrors (key, allDefines) =
178+ map (A.map (\_ -> errorTagger key)) allDefines
180+ Result.throwMany (concatMap toErrors pairs)
109-- VALIDATE STRUCTURED SOURCE
184-- VALIDATE STRUCTURED SOURCE
112−declarations :: [D.Source] -> Result.Result wrn Error.Error [D.Valid]
190+ -> Result.Result wrn Error.Error ([D.Valid], Valid.Effects)
113−declarations sourceDecls =
191+declarations tag sourceDecls =
114− do (Src decls cmds subs) <-
192+ do (decls, defines) <-
115− extractEffects =<< collapseComments sourceDecls
193+ partitionEffects <$> collapseComments sourceDecls
117 validDecls <-
195 validDecls <-
118 validateDecls decls
196 validateDecls decls
120− validCmds <-
198+ validEffects <-
121− validateEffects (Maybe.fromMaybe [] cmds)
199+ validateDefines tag defines
123− validSubs <-
201+ F.traverse_ id
124− validateEffects (Maybe.fromMaybe [] subs)
202+ (declDuplicates validDecls validEffects : map findBadTypeVars validDecls)
126− (\_ _ -> validDecls)
204+ return (validDecls, validEffects)
127− <$> declDuplicates validDecls
128− <*> T.traverse checkDecl validDecls
@@ -170,11 +246,11 @@ validateDeclsHelp
170 -> Result.Result wrn Error.Error [D.Valid]
246 -> Result.Result wrn Error.Error [D.Valid]
171validateDeclsHelp maybeComment (A.A region def) decls =
247validateDeclsHelp maybeComment (A.A region def) decls =
173− makeDef pat expr maybeType =
174− D.Def (Valid.Definition pat expr maybeType)
177 (region, fmap A.drop maybeComment)
250 (region, fmap A.drop maybeComment)
252+ makeDef pat expr maybeType =
253+ D.Def (Valid.Definition pat expr maybeType)
179 case def of
255 case def of
180 Source.Definition pat expr ->
256 Source.Definition pat expr ->
@@ -203,21 +279,21 @@ validateDeclsHelp maybeComment (A.A region def) decls =
204validateEffects
280validateEffects
205 :: [Commented Source.Effect]
281 :: [Commented Source.Effect]
206− -> Result.Result wrn Error.Error [A.Commented Valid.Effect]
282+ -> Result.Result wrn Error.Error [A.Commented Valid.Def]
207validateEffects effects =
283validateEffects effects =
208− case effects of
284+ case effects of
210− Result.ok []
286+ Result.ok []
212− A.A (region, maybeComment) effect : rest ->
288+ A.A (region, maybeComment) effect : rest ->
213− validateEffectsHelp (region, fmap A.drop maybeComment) effect rest
289+ validateEffectsHelp (region, fmap A.drop maybeComment) effect rest
216validateEffectsHelp
292validateEffectsHelp
217 :: (R.Region, Maybe String)
293 :: (R.Region, Maybe String)
218 -> Source.Effect
294 -> Source.Effect
219 -> [Commented Source.Effect]
295 -> [Commented Source.Effect]
220− -> Result.Result wrn Error.Error [A.Commented Valid.Effect]
296+ -> Result.Result wrn Error.Error [A.Commented Valid.Def]
221validateEffectsHelp ann effect remainingEffects =
297validateEffectsHelp ann effect remainingEffects =
222 case effect of
298 case effect of
223 Source.With _ _ ->
299 Source.With _ _ ->
@@ -225,7 +301,7 @@ validateEffectsHelp ann effect remainingEffects =
226 Source.Def pat expr ->
302 Source.Def pat expr ->
228− <$> validateDef Valid.Def ann pat expr Nothing
304+ <$> validateDef Valid.Definition ann pat expr Nothing
229 <*> validateEffects remainingEffects
305 <*> validateEffects remainingEffects
231 Source.Type name tipe ->
307 Source.Type name tipe ->
@@ -236,13 +312,47 @@ validateEffectsHelp ann effect remainingEffects =
236 A.A _ (Source.Def pat expr) : rest
312 A.A _ (Source.Def pat expr) : rest
237 | Pattern.isVar name pat ->
313 | Pattern.isVar name pat ->
239− <$> validateDef Valid.Def ann pat expr (Just tipe)
315+ <$> validateDef Valid.Definition ann pat expr (Just tipe)
240 <*> validateEffects rest
316 <*> validateEffects rest
243 Result.throw (fst ann) (Error.TypeWithoutDefinition name)
319 Result.throw (fst ann) (Error.TypeWithoutDefinition name)
323+ :: Commented Source.Effect
324+ -> Result.Result wrn Error.Error (A.Commented Valid.ForeignCmd)
325+validateForeignCmd (A.A (region, maybeComment) effect) =
328+ Result.throw region (error "TODO")
331+ Result.throw region (error "TODO")
333+ Source.Type name tipe ->
335+ A.A (region, fmap A.drop maybeComment) (Valid.Cmd name tipe)
339+ :: Commented Source.Effect
340+ -> Result.Result wrn Error.Error (A.Commented Valid.ForeignSub)
341+validateForeignSub (A.A (region, maybeComment) effect) =
343+ Source.With name expr ->
344+ do validExpr <- expression expr
346+ A.A (region, fmap A.drop maybeComment) (Valid.SubWith name validExpr)
349+ Result.throw region (error "TODO")
351+ Source.Type name tipe ->
353+ A.A (region, fmap A.drop maybeComment) (Valid.Sub name tipe)
247-- VALIDATE DEFINITIONS
357-- VALIDATE DEFINITIONS
@@ -398,8 +508,8 @@ second (value, expr) =
401− :: (Source.Expr, Source.Expr)
511+ :: (Source.Expr, Source.Expr)
402− -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
512+ -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
403both (expr1, expr2) =
513both (expr1, expr2) =
404 (,) <$> expression expr1 <*> expression expr2
514 (,) <$> expression expr1 <*> expression expr2
@@ -446,13 +556,18 @@ defDuplicates patterns =
446 |> detectDuplicates Error.DuplicateDefinition
556 |> detectDuplicates Error.DuplicateDefinition
449−declDuplicates :: [D.Valid] -> Result.Result wrn Error.Error ()
559+declDuplicates :: [D.Valid] -> Valid.Effects -> Result.Result wrn Error.Error ()
450−declDuplicates decls =
560+declDuplicates decls effects =
562+ (valueLists, typeLists) =
451− let (valueLists, typeLists) = unzip (map extractValues decls)
563+ unzip (map extractValues decls)
566+ extractEffectValues effects
453− (\_ _ -> ())
568+ (\_ _ -> ())
454− <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
569+ <$> detectDuplicates Error.DuplicateValueDeclaration (effectValues ++ concat valueLists)
455− <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
570+ <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
458extractValues :: D.Valid -> ([A.Located String], [A.Located String])
573extractValues :: D.Valid -> ([A.Located String], [A.Located String])
@@ -484,12 +599,42 @@ extractValues (A.A (region, _) decl) =
602+extractEffectValues :: Valid.Effects -> [A.Located String]
603+extractEffectValues effects =
608+ Valid.Effects cmds subs ->
610+ extractNames (Valid.Definition pat _ _) =
611+ Pattern.boundVars pat
613+ concatMap (extractNames . A.drop) (cmds ++ subs)
615+ Valid.ForeignEffects cmds subs ->
617+ extractCmdNames (A.A (region, _) (Valid.Cmd name _)) =
620+ extractSubNames (A.A (region, _) sub) =
626+ Valid.SubWith name _ ->
629+ map extractCmdNames cmds ++ map extractSubNames subs
488-- UNBOUND TYPE VARIABLES
633-- UNBOUND TYPE VARIABLES
491−checkDecl :: D.Valid -> Result.Result wrn Error.Error ()
636+findBadTypeVars :: D.Valid -> Result.Result wrn Error.Error ()
492−checkDecl (A.A (region,_) decl) =
637+findBadTypeVars (A.A (region,_) decl) =
493 case decl of
638 case decl of
494 D.Def _ ->
639 D.Def _ ->
495 return ()
640 return ()