1{-# OPTIONS_GHC -Wall #-}
2module Validate (module') where
4import Control.Monad (foldM)
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.Expression.Source as Source
12import qualified AST.Expression.Valid as Valid
13import qualified AST.Declaration as D
14import qualified AST.Module as Module
15import qualified AST.Module.Name as ModuleName
16import qualified AST.Pattern as Pattern
17import qualified AST.Type as Type
18import qualified Elm.Compiler.Imports as Imports
19import qualified Elm.Package as Package
20import Elm.Utils ((|>))
21import qualified Reporting.Annotation as A
22import qualified Reporting.Error.Syntax as Error
23import qualified Reporting.Region as R
24import qualified Reporting.Result as Result
31module' :: Module.Source -> Result.Result wrn Error.Error Module.Valid
32module' (Module.Module name path info) =
34 (ModuleName.Canonical pkgName _) =
37 (Module.Source tag settings docs exports imports decls) =
40 do validEffects <- validateModuleDecl tag settings
41 validDecls <- declarations decls
43 return $ Module.Module name path $
44 Module.Valid docs exports (addDefaults pkgName imports) validDecls validEffects
47-- determine if default imports should be added, only elm-lang/core is exempt
50 -> [Module.UserImport]
51 -> ([Module.DefaultImport], [Module.UserImport])
52addDefaults pkgName imports =
54 if pkgName == Package.coreName then
63 -> Module.SourceSettings
64 -> Result.Result wrn Error.Error Module.ValidEffects
65validateModuleDecl tag settings =
68 do noSettings Error.SettingsOnNormalModule settings
69 return Module.ValidNormal
72 do noSettings Error.SettingsOnForeignModule settings
73 return Module.ValidForeign
76 gatherEffectSettings settings
81 -> Module.SourceSettings
82 -> Result.Result wrn Error.Error ()
83noSettings errorMsg (A.A region settings) =
89 Result.throw region errorMsg
93 :: Module.SourceSettings
94 -> Result.Result wrn Error.Error Module.ValidEffects
95gatherEffectSettings (A.A _ pairs) =
96 uncurry Module.ValidEffect <$>
97 gatherEffectSettingsHelp (Nothing, Nothing) pairs
101 (Maybe (A.Located String), Maybe (A.Located String))
104gatherEffectSettingsHelp
106 -> [(A.Located String, A.Located String)]
107 -> Result.Result wrn Error.Error Effects
108gatherEffectSettingsHelp effects@(maybeCmd, maybeSub) pairs =
113 (A.A region name, effect) : rest ->
118 gatherEffectSettingsHelp (Just effect, maybeSub) rest
121 Result.throw region (Error.DuplicateSettingOnEffectModule name)
126 gatherEffectSettingsHelp (maybeCmd, Just effect) rest
129 Result.throw region (Error.DuplicateSettingOnEffectModule name)
132 Result.throw region (Error.BadSettingOnEffectModule name)
140 A.Annotated (R.Region, Maybe (A.Located String)) a
144 :: [D.CommentOr (A.Located a)]
145 -> Result.Result wrn Error.Error [Commented a]
146collapseComments listWithComments =
147 case listWithComments of
151 D.Comment msg : D.Whatever (A.A region a) : rest ->
154 A.A (region, Just msg) a
156 fmap (entry:) (collapseComments rest)
158 D.Comment (A.A region _) : D.Comment _ : _ ->
159 Result.throw region Error.CommentOnComment
161 [D.Comment (A.A region _)] ->
162 Result.throw region Error.CommentOnNothing
164 D.Whatever (A.A region a) : rest ->
167 A.A (region, Nothing) a
169 fmap (entry:) (collapseComments rest)
173-- VALIDATE STRUCTURED SOURCE
176declarations :: [D.Source] -> Result.Result wrn Error.Error [D.Valid]
177declarations sourceDecls =
179 collapseComments sourceDecls
185 (declDuplicates validDecls : map findBadTypeVars validDecls)
191-- VALIDATE DECLARATIONS
195 :: [Commented D.Source']
196 -> Result.Result wrn Error.Error [D.Valid]
197validateDecls commentedDecls =
198 case commentedDecls of
202 A.A (region, maybeComment) decl : rest ->
207 A.A (region, fmap A.drop maybeComment) validDecl
209 fmap (entry:) (validateDecls rest)
212 D.Union name tvars ctors ->
213 addRest (D.Union name tvars ctors)
215 D.Alias name tvars alias ->
216 addRest (D.Alias name tvars alias)
218 D.Fixity assoc prec op ->
219 addRest (D.Fixity assoc prec op)
222 validateDeclsHelp maybeComment def rest
226 :: Maybe (A.Located String)
228 -> [Commented D.Source']
229 -> Result.Result wrn Error.Error [D.Valid]
230validateDeclsHelp maybeComment (A.A region def) decls =
233 (region, fmap A.drop maybeComment)
235 makeDef pat expr maybeType =
236 D.Def (Valid.Definition pat expr maybeType)
239 Source.Definition pat expr ->
241 <$> validateDef makeDef ann pat expr Nothing
242 <*> validateDecls decls
244 Source.Annotation name tipe ->
246 A.A (_, Just (A.A commentRegion _)) _ : _ ->
247 Result.throw commentRegion (Error.CommentAfterAnnotation name)
249 A.A _ (D.Def (A.A _ (Source.Definition pat expr))) : rest
250 | Pattern.isVar name pat ->
252 <$> validateDef makeDef ann pat expr (Just tipe)
253 <*> validateDecls rest
256 Result.throw region (Error.TypeWithoutDefinition name)
260-- VALIDATE DEFINITIONS
263definitions :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
264definitions sourceDefs =
265 do validDefs <- definitionsHelp sourceDefs
266 let patterns = map (\(Valid.Definition p _ _) -> p) validDefs
267 defDuplicates patterns
271definitionsHelp :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
272definitionsHelp sourceDefs =
277 A.A region (Source.Definition pat expr) : rest ->
279 <$> fmap A.drop (validateDef Valid.Definition region pat expr Nothing)
280 <*> definitionsHelp rest
282 A.A r1 (Source.Annotation name tipe) : rest ->
284 A.A r2 (Source.Definition pat expr) : rest'
285 | Pattern.isVar name pat ->
287 <$> fmap A.drop (validateDef Valid.Definition (R.merge r1 r2) pat expr (Just tipe))
288 <*> definitionsHelp rest'
291 Result.throw r1 (Error.TypeWithoutDefinition name)
295 :: (Pattern.Raw -> Valid.Expr -> Maybe Type.Raw -> def)
300 -> Result.Result wrn Error.Error (A.Annotated annotation def)
301validateDef makeDef annotation pat expr maybeType =
302 do validExpr <- expression expr
303 validateDefPattern pat validExpr
304 return $ A.A annotation (makeDef pat validExpr maybeType)
307validateDefPattern :: Pattern.Raw -> Valid.Expr -> Result.Result wrn Error.Error ()
308validateDefPattern pattern body =
309 case fst (Expr.collectLambdas body) of
315 A.A _ (Pattern.Var _) ->
320 (A.A start _) = pattern
321 (A.A end _) = last args
323 Result.throw (R.merge start end) (Error.BadFunctionName (length args))
327-- VALIDATE EXPRESSIONS
330expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
331expression (A.A ann sourceExpression) =
333 case sourceExpression of
337 Lambda pattern body ->
339 <$> validatePattern pattern
342 Binop op leftExpr rightExpr ->
344 <$> expression leftExpr
345 <*> expression rightExpr
350 <*> T.traverse (\(p,b) -> (,) <$> validatePattern p <*> expression b) branches
353 Data name <$> T.traverse expression args
358 Range lowExpr highExpr ->
360 <$> expression lowExpr
361 <*> expression highExpr
363 ExplicitList expressions ->
365 <$> T.traverse expression expressions
367 App funcExpr argExpr ->
369 <$> expression funcExpr
370 <*> expression argExpr
372 If branches finally ->
374 <$> T.traverse both branches
375 <*> expression finally
377 Access record field ->
379 <$> expression record
382 Update record fields ->
384 <$> expression record
385 <*> T.traverse second fields
389 checkDups seenFields (field,_) =
390 if Set.member field seenFields then
391 Result.throw ann (Error.DuplicateFieldName field)
394 return (Set.insert field seenFields)
396 do _ <- foldM checkDups Set.empty fields
397 Record <$> T.traverse second fields
404 Cmd moduleName typeName ->
405 return (Cmd moduleName typeName)
407 Sub moduleName typeName ->
408 return (Sub moduleName typeName)
410 GLShader uid src gltipe ->
411 return (GLShader uid src gltipe)
414second :: (a, Source.Expr) -> Result.Result wrn Error.Error (a, Valid.Expr)
415second (value, expr) =
416 (,) value <$> expression expr
420 :: (Source.Expr, Source.Expr)
421 -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
423 (,) <$> expression expr1 <*> expression expr2
430validatePattern :: Pattern.Raw -> Result.Result wrn Error.Error Pattern.Raw
431validatePattern pattern =
432 do detectDuplicates Error.BadPattern (Pattern.boundVars pattern)
441 :: (String -> Error.Error)
442 -> [A.Located String]
443 -> Result.Result wrn Error.Error ()
444detectDuplicates tag names =
445 let add (A.A region name) dict =
446 Map.insertWith (++) name [region] dict
449 Map.toList (foldr add Map.empty pairs)
451 check (name, regions) =
454 Result.throw region (tag name)
459 F.traverse_ check (makeGroups names)
462defDuplicates :: [Pattern.Raw] -> Result.Result wrn Error.Error ()
463defDuplicates patterns =
464 concatMap Pattern.boundVars patterns
465 |> detectDuplicates Error.DuplicateDefinition
468declDuplicates :: [D.Valid] -> Result.Result wrn Error.Error ()
469declDuplicates decls =
471 (valueLists, typeLists) =
472 unzip (map extractValues decls)
475 <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
476 <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
479extractValues :: D.Valid -> ([A.Located String], [A.Located String])
480extractValues (A.A (region, _) decl) =
482 D.Def (Valid.Definition pattern _ _) ->
483 ( Pattern.boundVars pattern
487 D.Union name _ ctors ->
488 ( map (A.A region . fst) ctors
492 D.Alias name _ (A.A _ (Type.RRecord _ _)) ->
509-- UNBOUND TYPE VARIABLES
512findBadTypeVars :: D.Valid -> Result.Result wrn Error.Error ()
513findBadTypeVars (A.A (region,_) decl) =
518 D.Union name boundVars ctors ->
519 case diff boundVars (concatMap freeVars (concatMap snd ctors)) of
525 (Error.UnboundTypeVarsInUnion name boundVars unbound)
527 D.Alias name boundVars tipe ->
528 case diff boundVars (freeVars tipe) of
534 (Error.UnboundTypeVarsInAlias name boundVars unbound)
538 (Error.UnusedTypeVarsInAlias name boundVars unused)
542 (Error.MessyTypeVarsInAlias name boundVars unused unbound)
548diff :: [String] -> [A.Located String] -> ([String], [String])
555 Set.fromList (map A.drop right)
557 ( Set.toList (Set.difference leftSet rightSet)
558 , Set.toList (Set.difference rightSet leftSet)
563freeVars :: Type.Raw -> [A.Located String]
564freeVars (A.A region tipe) =
566 Type.RLambda t1 t2 ->
567 freeVars t1 ++ freeVars t2
576 concatMap freeVars (t:ts)
578 Type.RRecord fields ext ->
579 maybe [] freeVars ext
580 ++ 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