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 validEffects <- validateModuleDecl tag settings
42 validDecls <- declarations decls
44 return $ Module.Module name path $
45 Module.Valid docs exports (addDefaults pkgName imports) validDecls validEffects
48-- determine if default imports should be added, only elm-lang/core is exempt
51 -> [Module.UserImport]
52 -> ([Module.DefaultImport], [Module.UserImport])
53addDefaults pkgName imports =
55 if pkgName == Package.coreName then
64 -> Module.SourceSettings
65 -> Result.Result wrn Error.Error Fx.Effects
66validateModuleDecl tag settings@(A.A _ pairs) =
69 do noSettings Error.SettingsOnNormalModule settings
73 do noSettings Error.SettingsOnForeignModule settings
76 Module.Effect tagRegion ->
78 collectSettings (A.A region setting, userValue) dict =
79 Map.insertWith (++) setting [(region, userValue)] dict
82 foldr collectSettings Map.empty pairs
84 do managerType <- toManagerType tagRegion settingsDict
86 Fx.Info tagRegion (error "TODO") (error "TODO") (error "TODO") managerType
91 -> Module.SourceSettings
92 -> Result.Result wrn Error.Error ()
93noSettings errorMsg (A.A region settings) =
99 Result.throw region errorMsg
104 -> Map.Map String [(R.Region, A.Located String)]
105 -> Result.Result wrn Error.Error Fx.ManagerType
106toManagerType tagRegion settingsDict =
108 toErrors name entries =
109 map (\entry -> A.A (fst entry) (Error.BadSettingOnEffectModule name)) entries
113 |> Map.delete "command"
114 |> Map.delete "subscription"
115 |> Map.mapWithKey toErrors
119 do when (not (null errors)) (Result.throwMany errors)
121 (,) <$> extractOne "command" settingsDict
122 <*> extractOne "subscription" settingsDict
125 (Nothing, Nothing) ->
126 Result.throw tagRegion Error.NoSettingsOnEffectModule
128 (Just cmd, Nothing) ->
129 return (Fx.CmdManager cmd)
131 (Nothing, Just sub) ->
132 return (Fx.SubManager sub)
134 (Just cmd, Just sub) ->
135 return (Fx.FxManager cmd sub)
140 -> Map.Map String [(R.Region, A.Located String)]
141 -> Result.Result w Error.Error (Maybe (A.Located String))
142extractOne name settingsDict =
143 case Map.lookup name settingsDict of
148 error "Empty lists should never be added to the dictionary of effect module settings."
150 Just [(_, userType)] ->
151 return (Just userType)
153 Just ((region, _) : _) ->
154 Result.throw region (Error.DuplicateSettingOnEffectModule name)
162 A.Annotated (R.Region, Maybe (A.Located String)) a
166 :: [D.CommentOr (A.Located a)]
167 -> Result.Result wrn Error.Error [Commented a]
168collapseComments listWithComments =
169 case listWithComments of
173 D.Comment msg : D.Whatever (A.A region a) : rest ->
176 A.A (region, Just msg) a
178 fmap (entry:) (collapseComments rest)
180 D.Comment (A.A region _) : D.Comment _ : _ ->
181 Result.throw region Error.CommentOnComment
183 [D.Comment (A.A region _)] ->
184 Result.throw region Error.CommentOnNothing
186 D.Whatever (A.A region a) : rest ->
189 A.A (region, Nothing) a
191 fmap (entry:) (collapseComments rest)
195-- VALIDATE STRUCTURED SOURCE
198declarations :: [D.Source] -> Result.Result wrn Error.Error [D.Valid]
199declarations sourceDecls =
201 collapseComments sourceDecls
207 (declDuplicates validDecls : map findBadTypeVars validDecls)
213-- VALIDATE DECLARATIONS
217 :: [Commented D.Source']
218 -> Result.Result wrn Error.Error [D.Valid]
219validateDecls commentedDecls =
220 case commentedDecls of
224 A.A (region, maybeComment) decl : rest ->
229 A.A (region, fmap A.drop maybeComment) validDecl
231 fmap (entry:) (validateDecls rest)
234 D.Union name tvars ctors ->
235 addRest (D.Union name tvars ctors)
237 D.Alias name tvars alias ->
238 addRest (D.Alias name tvars alias)
240 D.Fixity assoc prec op ->
241 addRest (D.Fixity assoc prec op)
244 validateDeclsHelp maybeComment def rest
248 :: Maybe (A.Located String)
250 -> [Commented D.Source']
251 -> Result.Result wrn Error.Error [D.Valid]
252validateDeclsHelp maybeComment (A.A region def) decls =
255 (region, fmap A.drop maybeComment)
257 makeDef pat expr maybeType =
258 D.Def (Valid.Definition pat expr maybeType)
261 Source.Definition pat expr ->
263 <$> validateDef makeDef ann pat expr Nothing
264 <*> validateDecls decls
266 Source.Annotation name tipe ->
268 A.A (_, Just (A.A commentRegion _)) _ : _ ->
269 Result.throw commentRegion (Error.CommentAfterAnnotation name)
271 A.A _ (D.Def (A.A _ (Source.Definition pat expr))) : rest
272 | Pattern.isVar name pat ->
274 <$> validateDef makeDef ann pat expr (Just tipe)
275 <*> validateDecls rest
278 Result.throw region (Error.TypeWithoutDefinition name)
282-- VALIDATE DEFINITIONS
285definitions :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
286definitions sourceDefs =
287 do validDefs <- definitionsHelp sourceDefs
288 let patterns = map (\(Valid.Definition p _ _) -> p) validDefs
289 defDuplicates patterns
293definitionsHelp :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
294definitionsHelp sourceDefs =
299 A.A region (Source.Definition pat expr) : rest ->
301 <$> fmap A.drop (validateDef Valid.Definition region pat expr Nothing)
302 <*> definitionsHelp rest
304 A.A r1 (Source.Annotation name tipe) : rest ->
306 A.A r2 (Source.Definition pat expr) : rest'
307 | Pattern.isVar name pat ->
309 <$> fmap A.drop (validateDef Valid.Definition (R.merge r1 r2) pat expr (Just tipe))
310 <*> definitionsHelp rest'
313 Result.throw r1 (Error.TypeWithoutDefinition name)
317 :: (Pattern.Raw -> Valid.Expr -> Maybe Type.Raw -> def)
322 -> Result.Result wrn Error.Error (A.Annotated annotation def)
323validateDef makeDef annotation pat expr maybeType =
324 do validExpr <- expression expr
325 validateDefPattern pat validExpr
326 return $ A.A annotation (makeDef pat validExpr maybeType)
329validateDefPattern :: Pattern.Raw -> Valid.Expr -> Result.Result wrn Error.Error ()
330validateDefPattern pattern body =
331 case fst (Expr.collectLambdas body) of
337 A.A _ (Pattern.Var _) ->
342 (A.A start _) = pattern
343 (A.A end _) = last args
345 Result.throw (R.merge start end) (Error.BadFunctionName (length args))
349-- VALIDATE EXPRESSIONS
352expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
353expression (A.A ann sourceExpression) =
355 case sourceExpression of
359 Lambda pattern body ->
361 <$> validatePattern pattern
364 Binop op leftExpr rightExpr ->
366 <$> expression leftExpr
367 <*> expression rightExpr
372 <*> T.traverse (\(p,b) -> (,) <$> validatePattern p <*> expression b) branches
375 Data name <$> T.traverse expression args
380 Range lowExpr highExpr ->
382 <$> expression lowExpr
383 <*> expression highExpr
385 ExplicitList expressions ->
387 <$> T.traverse expression expressions
389 App funcExpr argExpr ->
391 <$> expression funcExpr
392 <*> expression argExpr
394 If branches finally ->
396 <$> T.traverse both branches
397 <*> expression finally
399 Access record field ->
401 <$> expression record
404 Update record fields ->
406 <$> expression record
407 <*> T.traverse second fields
411 checkDups seenFields (field,_) =
412 if Set.member field seenFields then
413 Result.throw ann (Error.DuplicateFieldName field)
416 return (Set.insert field seenFields)
418 do _ <- foldM checkDups Set.empty fields
419 Record <$> T.traverse second fields
426 Cmd moduleName typeName ->
427 return (Cmd moduleName typeName)
429 Sub moduleName typeName ->
430 return (Sub moduleName typeName)
432 SaveEnv moduleName effects ->
433 return (SaveEnv moduleName effects)
435 GLShader uid src gltipe ->
436 return (GLShader uid src gltipe)
439second :: (a, Source.Expr) -> Result.Result wrn Error.Error (a, Valid.Expr)
440second (value, expr) =
441 (,) value <$> expression expr
445 :: (Source.Expr, Source.Expr)
446 -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
448 (,) <$> expression expr1 <*> expression expr2
455validatePattern :: Pattern.Raw -> Result.Result wrn Error.Error Pattern.Raw
456validatePattern pattern =
457 do detectDuplicates Error.BadPattern (Pattern.boundVars pattern)
466 :: (String -> Error.Error)
467 -> [A.Located String]
468 -> Result.Result wrn Error.Error ()
469detectDuplicates tag names =
470 let add (A.A region name) dict =
471 Map.insertWith (++) name [region] dict
474 Map.toList (foldr add Map.empty pairs)
476 check (name, regions) =
479 Result.throw region (tag name)
484 F.traverse_ check (makeGroups names)
487defDuplicates :: [Pattern.Raw] -> Result.Result wrn Error.Error ()
488defDuplicates patterns =
489 concatMap Pattern.boundVars patterns
490 |> detectDuplicates Error.DuplicateDefinition
493declDuplicates :: [D.Valid] -> Result.Result wrn Error.Error ()
494declDuplicates decls =
496 (valueLists, typeLists) =
497 unzip (map extractValues decls)
500 <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
501 <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
504extractValues :: D.Valid -> ([A.Located String], [A.Located String])
505extractValues (A.A (region, _) decl) =
507 D.Def (Valid.Definition pattern _ _) ->
508 ( Pattern.boundVars pattern
512 D.Union name _ ctors ->
513 ( map (A.A region . fst) ctors
517 D.Alias name _ (A.A _ (Type.RRecord _ _)) ->
534-- UNBOUND TYPE VARIABLES
537findBadTypeVars :: D.Valid -> Result.Result wrn Error.Error ()
538findBadTypeVars (A.A (region,_) decl) =
543 D.Union name boundVars ctors ->
544 case diff boundVars (concatMap freeVars (concatMap snd ctors)) of
550 (Error.UnboundTypeVarsInUnion name boundVars unbound)
552 D.Alias name boundVars tipe ->
553 case diff boundVars (freeVars tipe) of
559 (Error.UnboundTypeVarsInAlias name boundVars unbound)
563 (Error.UnusedTypeVarsInAlias name boundVars unused)
567 (Error.MessyTypeVarsInAlias name boundVars unused unbound)
573diff :: [String] -> [A.Located String] -> ([String], [String])
580 Set.fromList (map A.drop right)
582 ( Set.toList (Set.difference leftSet rightSet)
583 , Set.toList (Set.difference rightSet leftSet)
588freeVars :: Type.Raw -> [A.Located String]
589freeVars (A.A region tipe) =
591 Type.RLambda t1 t2 ->
592 freeVars t1 ++ freeVars t2
601 concatMap freeVars (t:ts)
603 Type.RRecord fields ext ->
604 maybe [] freeVars ext
605 ++ 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