1{-# OPTIONS_GHC -Wall #-}
2module Validate (module') where
4import Control.Monad (foldM, when)
5import qualified Data.Map as Map
6import qualified Data.Set as Set
7import qualified Data.Foldable as F
8import qualified Data.Traversable as T
10import AST.Expression.General as Expr
11import qualified AST.Effects as Fx
12import qualified AST.Expression.Source as Source
13import qualified AST.Expression.Valid as Valid
14import qualified AST.Declaration as D
15import qualified AST.Module as Module
16import qualified AST.Module.Name as ModuleName
17import qualified AST.Pattern as Pattern
18import qualified AST.Type as Type
19import qualified Elm.Compiler.Imports as Imports
20import qualified Elm.Package as Package
21import Elm.Utils ((|>))
22import qualified Reporting.Annotation as A
23import qualified Reporting.Error.Syntax as Error
24import qualified Reporting.Region as R
25import qualified Reporting.Result as Result
32module' :: Module.Source -> Result.Result wrn Error.Error Module.Valid
33module' (Module.Module name path info) =
35 (ModuleName.Canonical pkgName _) =
38 (Module.Source tag settings docs exports imports decls) =
41 do validDecls <- declarations decls
42 validEffects <- validateEffects tag settings validDecls
44 return $ Module.Module name path $
45 Module.Valid docs exports (addDefaults pkgName imports) validDecls validEffects
54 -> [Module.UserImport]
55 -> ([Module.DefaultImport], [Module.UserImport])
56addDefaults pkgName imports =
58 if pkgName == Package.coreName then
71 -> Module.SourceSettings
73 -> Result.Result wrn Error.Error Fx.Effects
74validateEffects tag settings@(A.A _ pairs) decls =
77 do noSettings Error.SettingsOnNormalModule settings
81 do noSettings Error.SettingsOnForeignModule settings
84 Module.Effect tagRegion ->
86 collectSettings (A.A region setting, userValue) dict =
87 Map.insertWith (++) setting [(region, userValue)] dict
90 foldr collectSettings Map.empty pairs
92 do managerType <- toManagerType tagRegion settingsDict
93 (r0, r1, r2) <- getManagerRegions tagRegion Nothing Nothing Nothing decls
94 return (Fx.Effect (Fx.Info tagRegion r0 r1 r2 managerType))
99 -> Module.SourceSettings
100 -> Result.Result wrn Error.Error ()
101noSettings errorMsg (A.A region settings) =
107 Result.throw region errorMsg
112 -> Map.Map String [(R.Region, A.Located String)]
113 -> Result.Result wrn Error.Error Fx.ManagerType
114toManagerType tagRegion settingsDict =
116 toErrors name entries =
117 map (\entry -> A.A (fst entry) (Error.BadSettingOnEffectModule name)) entries
121 |> Map.delete "command"
122 |> Map.delete "subscription"
123 |> Map.mapWithKey toErrors
127 do when (not (null errors)) (Result.throwMany errors)
129 (,) <$> extractOne "command" settingsDict
130 <*> extractOne "subscription" settingsDict
133 (Nothing, Nothing) ->
134 Result.throw tagRegion Error.NoSettingsOnEffectModule
136 (Just cmd, Nothing) ->
137 return (Fx.CmdManager cmd)
139 (Nothing, Just sub) ->
140 return (Fx.SubManager sub)
142 (Just cmd, Just sub) ->
143 return (Fx.FxManager cmd sub)
148 -> Map.Map String [(R.Region, A.Located String)]
149 -> Result.Result w Error.Error (Maybe (A.Located String))
150extractOne name settingsDict =
151 case Map.lookup name settingsDict of
156 error "Empty lists should never be added to the dictionary of effect module settings."
158 Just [(_, userType)] ->
159 return (Just userType)
161 Just ((region, _) : _) ->
162 Result.throw region (Error.DuplicateSettingOnEffectModule name)
175 -> Result.Result w Error.Error (R.Region, R.Region, R.Region)
176getManagerRegions tagRegion r0 r1 r2 decls =
180 <$> requireRegion tagRegion "init" r0
181 <*> requireRegion tagRegion "onEffects" r1
182 <*> requireRegion tagRegion "onSelfMsg" r2
185 case getDefInfo decl of
186 Just ("init", region) ->
187 getManagerRegions tagRegion (Just region) r1 r2 rest
189 Just ("onEffects", region) ->
190 getManagerRegions tagRegion r0 (Just region) r2 rest
192 Just ("onSelfMsg", region) ->
193 getManagerRegions tagRegion r0 r1 (Just region) rest
196 getManagerRegions tagRegion r0 r1 r2 rest
199getDefInfo :: D.Valid -> Maybe (String, R.Region)
202 A.A region (D.Def (Valid.Definition (A.A _ (Pattern.Var name)) _ _)) ->
203 Just (name, fst region)
209requireRegion :: R.Region -> String -> Maybe R.Region -> Result.Result w Error.Error R.Region
210requireRegion tagRegion name maybeRegion =
216 Result.throw tagRegion (Error.MissingManagerOnEffectModule name)
224 A.Annotated (R.Region, Maybe (A.Located String)) a
228 :: [D.CommentOr (A.Located a)]
229 -> Result.Result wrn Error.Error [Commented a]
230collapseComments listWithComments =
231 case listWithComments of
235 D.Comment msg : D.Whatever (A.A region a) : rest ->
238 A.A (region, Just msg) a
240 fmap (entry:) (collapseComments rest)
242 D.Comment (A.A region _) : D.Comment _ : _ ->
243 Result.throw region Error.CommentOnComment
245 [D.Comment (A.A region _)] ->
246 Result.throw region Error.CommentOnNothing
248 D.Whatever (A.A region a) : rest ->
251 A.A (region, Nothing) a
253 fmap (entry:) (collapseComments rest)
257-- VALIDATE STRUCTURED SOURCE
260declarations :: [D.Source] -> Result.Result wrn Error.Error [D.Valid]
261declarations sourceDecls =
263 collapseComments sourceDecls
269 (declDuplicates validDecls : map findBadTypeVars validDecls)
275-- VALIDATE DECLARATIONS
279 :: [Commented D.Source']
280 -> Result.Result wrn Error.Error [D.Valid]
281validateDecls commentedDecls =
282 case commentedDecls of
286 A.A (region, maybeComment) decl : rest ->
291 A.A (region, fmap A.drop maybeComment) validDecl
293 fmap (entry:) (validateDecls rest)
296 D.Union name tvars ctors ->
297 addRest (D.Union name tvars ctors)
299 D.Alias name tvars alias ->
300 addRest (D.Alias name tvars alias)
302 D.Fixity assoc prec op ->
303 addRest (D.Fixity assoc prec op)
306 validateDeclsHelp maybeComment def rest
310 :: Maybe (A.Located String)
312 -> [Commented D.Source']
313 -> Result.Result wrn Error.Error [D.Valid]
314validateDeclsHelp maybeComment (A.A region def) decls =
317 (region, fmap A.drop maybeComment)
319 makeDef pat expr maybeType =
320 D.Def (Valid.Definition pat expr maybeType)
323 Source.Definition pat expr ->
325 <$> validateDef makeDef ann pat expr Nothing
326 <*> validateDecls decls
328 Source.Annotation name tipe ->
330 A.A (_, Just (A.A commentRegion _)) _ : _ ->
331 Result.throw commentRegion (Error.CommentAfterAnnotation name)
333 A.A _ (D.Def (A.A _ (Source.Definition pat expr))) : rest
334 | Pattern.isVar name pat ->
336 <$> validateDef makeDef ann pat expr (Just tipe)
337 <*> validateDecls rest
340 Result.throw region (Error.TypeWithoutDefinition name)
344-- VALIDATE DEFINITIONS
347definitions :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
348definitions sourceDefs =
349 do validDefs <- definitionsHelp sourceDefs
350 let patterns = map (\(Valid.Definition p _ _) -> p) validDefs
351 defDuplicates patterns
355definitionsHelp :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
356definitionsHelp sourceDefs =
361 A.A region (Source.Definition pat expr) : rest ->
363 <$> fmap A.drop (validateDef Valid.Definition region pat expr Nothing)
364 <*> definitionsHelp rest
366 A.A r1 (Source.Annotation name tipe) : rest ->
368 A.A r2 (Source.Definition pat expr) : rest'
369 | Pattern.isVar name pat ->
371 <$> fmap A.drop (validateDef Valid.Definition (R.merge r1 r2) pat expr (Just tipe))
372 <*> definitionsHelp rest'
375 Result.throw r1 (Error.TypeWithoutDefinition name)
379 :: (Pattern.Raw -> Valid.Expr -> Maybe Type.Raw -> def)
384 -> Result.Result wrn Error.Error (A.Annotated annotation def)
385validateDef makeDef annotation pat expr maybeType =
386 do validExpr <- expression expr
387 validateDefPattern pat validExpr
388 return $ A.A annotation (makeDef pat validExpr maybeType)
391validateDefPattern :: Pattern.Raw -> Valid.Expr -> Result.Result wrn Error.Error ()
392validateDefPattern pattern body =
393 case fst (Expr.collectLambdas body) of
399 A.A _ (Pattern.Var _) ->
404 (A.A start _) = pattern
405 (A.A end _) = last args
407 Result.throw (R.merge start end) (Error.BadFunctionName (length args))
411-- VALIDATE EXPRESSIONS
414expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
415expression (A.A ann sourceExpression) =
417 case sourceExpression of
421 Lambda pattern body ->
423 <$> validatePattern pattern
426 Binop op leftExpr rightExpr ->
428 <$> expression leftExpr
429 <*> expression rightExpr
434 <*> T.traverse (\(p,b) -> (,) <$> validatePattern p <*> expression b) branches
437 Data name <$> T.traverse expression args
442 Range lowExpr highExpr ->
444 <$> expression lowExpr
445 <*> expression highExpr
447 ExplicitList expressions ->
449 <$> T.traverse expression expressions
451 App funcExpr argExpr ->
453 <$> expression funcExpr
454 <*> expression argExpr
456 If branches finally ->
458 <$> T.traverse both branches
459 <*> expression finally
461 Access record field ->
463 <$> expression record
466 Update record fields ->
468 <$> expression record
469 <*> T.traverse second fields
473 checkDups seenFields (field,_) =
474 if Set.member field seenFields then
475 Result.throw ann (Error.DuplicateFieldName field)
478 return (Set.insert field seenFields)
480 do _ <- foldM checkDups Set.empty fields
481 Record <$> T.traverse second fields
488 Cmd moduleName typeName ->
489 return (Cmd moduleName typeName)
491 Sub moduleName typeName ->
492 return (Sub moduleName typeName)
494 SaveEnv moduleName effects ->
495 return (SaveEnv moduleName effects)
497 GLShader uid src gltipe ->
498 return (GLShader uid src gltipe)
501second :: (a, Source.Expr) -> Result.Result wrn Error.Error (a, Valid.Expr)
502second (value, expr) =
503 (,) value <$> expression expr
507 :: (Source.Expr, Source.Expr)
508 -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
510 (,) <$> expression expr1 <*> expression expr2
517validatePattern :: Pattern.Raw -> Result.Result wrn Error.Error Pattern.Raw
518validatePattern pattern =
519 do detectDuplicates Error.BadPattern (Pattern.boundVars pattern)
528 :: (String -> Error.Error)
529 -> [A.Located String]
530 -> Result.Result wrn Error.Error ()
531detectDuplicates tag names =
532 let add (A.A region name) dict =
533 Map.insertWith (++) name [region] dict
536 Map.toList (foldr add Map.empty pairs)
538 check (name, regions) =
541 Result.throw region (tag name)
546 F.traverse_ check (makeGroups names)
549defDuplicates :: [Pattern.Raw] -> Result.Result wrn Error.Error ()
550defDuplicates patterns =
551 concatMap Pattern.boundVars patterns
552 |> detectDuplicates Error.DuplicateDefinition
555declDuplicates :: [D.Valid] -> Result.Result wrn Error.Error ()
556declDuplicates decls =
558 (valueLists, typeLists) =
559 unzip (map extractValues decls)
562 <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
563 <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
566extractValues :: D.Valid -> ([A.Located String], [A.Located String])
567extractValues (A.A (region, _) decl) =
569 D.Def (Valid.Definition pattern _ _) ->
570 ( Pattern.boundVars pattern
574 D.Union name _ ctors ->
575 ( map (A.A region . fst) ctors
579 D.Alias name _ (A.A _ (Type.RRecord _ _)) ->
596-- UNBOUND TYPE VARIABLES
599findBadTypeVars :: D.Valid -> Result.Result wrn Error.Error ()
600findBadTypeVars (A.A (region,_) decl) =
605 D.Union name boundVars ctors ->
606 case diff boundVars (concatMap freeVars (concatMap snd ctors)) of
612 (Error.UnboundTypeVarsInUnion name boundVars unbound)
614 D.Alias name boundVars tipe ->
615 case diff boundVars (freeVars tipe) of
621 (Error.UnboundTypeVarsInAlias name boundVars unbound)
625 (Error.UnusedTypeVarsInAlias name boundVars unused)
629 (Error.MessyTypeVarsInAlias name boundVars unused unbound)
635diff :: [String] -> [A.Located String] -> ([String], [String])
642 Set.fromList (map A.drop right)
644 ( Set.toList (Set.difference leftSet rightSet)
645 , Set.toList (Set.difference rightSet leftSet)
650freeVars :: Type.Raw -> [A.Located String]
651freeVars (A.A region tipe) =
653 Type.RLambda t1 t2 ->
654 freeVars t1 ++ freeVars t2
663 concatMap freeVars (t:ts)
665 Type.RRecord fields ext ->
666 maybe [] freeVars ext
667 ++ concatMap (freeVars . snd) fields
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list