1{-# OPTIONS_GHC -Wall #-}
2module Validate (declarations) 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.Pattern as Pattern
15import qualified AST.Type as Type
16import Elm.Utils ((|>))
17import qualified Reporting.Annotation as A
18import qualified Reporting.Error.Syntax as Error
19import qualified Reporting.Region as R
20import qualified Reporting.Result as Result
23-- VALIDATE DECLARATIONS
28 -> Result.Result wrn Error.Error [D.ValidDecl]
29declarations isRoot sourceDecls =
30 do validDecls <- validateDecls Nothing sourceDecls
32 <$> declDuplicates validDecls
33 <*> T.traverse (checkDecl isRoot) validDecls
39 -> Result.Result wrn Error.Error [D.ValidDecl]
40validateDecls maybeComment sourceDecls =
48 validateDecls (Just comment) decls
51 validateDeclsHelp maybeComment decl decls
56 -> A.Located D.SourceDecl'
58 -> Result.Result wrn Error.Error [D.ValidDecl]
59validateDeclsHelp comment (A.A region decl) decls =
60 let addRest validDecl =
61 (:) (A.A (region, comment) validDecl)
62 <$> validateDecls Nothing decls
65 D.Datatype name tvars ctors ->
66 addRest (D.Datatype name tvars ctors)
68 D.TypeAlias name tvars alias ->
69 addRest (D.TypeAlias name tvars alias)
71 D.Fixity assoc prec op ->
72 addRest (D.Fixity assoc prec op)
75 defHelp comment def decls
78 portHelp comment region port decls
81-- VALIDATE DEFINITIONS IN DECLARATIONS
87 -> Result.Result wrn Error.Error [D.ValidDecl]
88defHelp comment (A.A region def) decls =
89 let addRest def' rest =
90 (:) (A.A (region, comment) (D.Definition def'))
91 <$> validateDecls Nothing rest
94 Source.Definition pat expr ->
95 do expr' <- expression expr
96 let def' = Valid.Definition pat expr' Nothing
100 Source.TypeAnnotation name tipe ->
102 D.Decl (A.A _ (D.Definition (A.A _
103 (Source.Definition pat@(A.A _ (Pattern.Var name')) expr)))) : rest
105 do expr' <- expression expr
106 let def' = Valid.Definition pat expr' (Just tipe)
111 Result.throw region (Error.TypeWithoutDefinition name)
114-- VALIDATE PORTS IN DECLARATIONS
121 -> Result.Result wrn Error.Error [D.ValidDecl]
122portHelp comment region port decls =
123 let addRest port' rest =
124 (:) (A.A (region,comment) (D.Port port'))
125 <$> validateDecls Nothing rest
128 D.PortDefinition name _ ->
129 Result.throw region (Error.PortWithoutAnnotation name)
131 D.PortAnnotation name tipe ->
133 D.Decl (A.A _ (D.Port (D.PortDefinition name' expr))) : rest
135 do expr' <- expression expr
136 let port' = D.Out name expr' tipe
140 addRest (D.In name tipe) decls
143-- VALIDATE DEFINITIONS
145definitions :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
146definitions sourceDefs =
147 do validDefs <- definitionsHelp sourceDefs
148 let patterns = map (\(Valid.Definition p _ _) -> p) validDefs
149 defDuplicates patterns
153definitionsHelp :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
154definitionsHelp sourceDefs =
159 A.A _ (Source.Definition pat expr) : rest ->
160 do expr' <- expression expr
161 let def = Valid.Definition pat expr' Nothing
163 (:) def <$> definitionsHelp rest
165 A.A region (Source.TypeAnnotation name tipe) : rest ->
167 A.A _ (Source.Definition pat@(A.A _ (Pattern.Var name')) expr) : rest'
169 do expr' <- expression expr
170 let def = Valid.Definition pat expr' (Just tipe)
172 (:) def <$> definitionsHelp rest'
175 Result.throw region (Error.TypeWithoutDefinition name)
178checkDefinition :: Valid.Def -> Result.Result wrn Error.Error ()
179checkDefinition (Valid.Definition pattern body _) =
180 case fst (Expr.collectLambdas body) of
186 A.A _ (Pattern.Var funcName) ->
187 checkArguments funcName args
191 (A.A start _) = pattern
192 (A.A end _) = last args
194 Result.throw (R.merge start end) (Error.BadFunctionName (length args))
197checkArguments :: String -> [Pattern.RawPattern] -> Result.Result wrn Error.Error ()
198checkArguments funcName args =
201 concatMap Pattern.boundVars args
203 checkDups seenArgs (A.A region arg) =
204 if Set.member arg seenArgs then
205 Result.throw region (Error.DuplicateArgument funcName arg)
208 return (Set.insert arg seenArgs)
210 foldM_ checkDups Set.empty vars
213-- VALIDATE EXPRESSIONS
215expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
216expression (A.A ann sourceExpression) =
218 case sourceExpression of
222 Lambda pattern body ->
224 <$> validatePattern pattern
227 Binop op leftExpr rightExpr ->
229 <$> expression leftExpr
230 <*> expression rightExpr
235 <*> T.traverse (\(p,b) -> (,) <$> validatePattern p <*> expression b) branches
238 Data name <$> T.traverse expression args
243 Range lowExpr highExpr ->
245 <$> expression lowExpr
246 <*> expression highExpr
248 ExplicitList expressions ->
250 <$> T.traverse expression expressions
252 App funcExpr argExpr ->
254 <$> expression funcExpr
255 <*> expression argExpr
257 If branches finally ->
259 <$> T.traverse both branches
260 <*> expression finally
262 Access record field ->
264 <$> expression record
267 Update record fields ->
269 <$> expression record
270 <*> T.traverse second fields
274 checkDups seenFields (field,_) =
275 if Set.member field seenFields then
276 Result.throw ann (Error.DuplicateFieldName field)
279 return (Set.insert field seenFields)
281 do foldM_ checkDups Set.empty fields
282 Record <$> T.traverse second fields
289 GLShader uid src gltipe ->
290 return (GLShader uid src gltipe)
296 return (In name tipe)
298 Out name expr tipe ->
299 do expr' <- expression expr
300 return (Out name expr' tipe)
302 Task name expr tipe ->
303 do expr' <- expression expr
304 return (Task name expr' tipe)
307second :: (a, Source.Expr) -> Result.Result wrn Error.Error (a, Valid.Expr)
308second (value, expr) =
309 (,) value <$> expression expr
313 :: (Source.Expr, Source.Expr)
314 -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
316 (,) <$> expression expr1 <*> expression expr2
321validatePattern :: Pattern.RawPattern -> Result.Result wrn Error.Error Pattern.RawPattern
322validatePattern pattern =
323 do detectDuplicates Error.BadPattern (Pattern.boundVars pattern)
330 :: (String -> Error.Error)
331 -> [A.Located String]
332 -> Result.Result wrn Error.Error ()
333detectDuplicates tag names =
334 let add (A.A region name) dict =
335 Map.insertWith (++) name [region] dict
338 Map.toList (foldr add Map.empty pairs)
340 check (name, regions) =
343 Result.throw region (tag name)
348 F.traverse_ check (makeGroups names)
352 :: [Pattern.RawPattern]
353 -> Result.Result wrn Error.Error ()
354defDuplicates patterns =
355 concatMap Pattern.boundVars patterns
356 |> detectDuplicates Error.DuplicateDefinition
359declDuplicates :: [D.ValidDecl] -> Result.Result wrn Error.Error ()
360declDuplicates decls =
361 let (valueLists, typeLists) = unzip (map extractValues decls)
364 <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
365 <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
368extractValues :: D.ValidDecl -> ([A.Located String], [A.Located String])
369extractValues (A.A (region, _) decl) =
371 D.Definition (Valid.Definition pattern _ _) ->
372 ( Pattern.boundVars pattern
376 D.Datatype name _ ctors ->
377 ( map (A.A region . fst) ctors
381 D.TypeAlias name _ (A.A _ (Type.RRecord _ _)) ->
386 D.TypeAlias name _ _ ->
392 ( [A.A region (D.validPortName port)]
402-- UNBOUND TYPE VARIABLES
404checkDecl :: Bool -> D.ValidDecl -> Result.Result wrn Error.Error ()
405checkDecl isRoot (A.A (region,_) decl) =
410 D.Datatype name boundVars ctors ->
411 case diff boundVars (concatMap freeVars (concatMap snd ctors)) of
417 (Error.UnboundTypeVarsInUnion name boundVars unbound)
419 D.TypeAlias name boundVars tipe ->
420 case diff boundVars (freeVars tipe) of
426 (Error.UnboundTypeVarsInAlias name boundVars unbound)
430 (Error.UnusedTypeVarsInAlias name boundVars unused)
434 (Error.MessyTypeVarsInAlias name boundVars unused unbound)
441 Result.throw region Error.UnexpectedPort
447diff :: [String] -> [A.Located String] -> ([String], [String])
454 Set.fromList (map A.drop right)
456 ( Set.toList (Set.difference leftSet rightSet)
457 , Set.toList (Set.difference rightSet leftSet)
462freeVars :: Type.Raw -> [A.Located String]
463freeVars (A.A region tipe) =
465 Type.RLambda t1 t2 ->
466 freeVars t1 ++ freeVars t2
475 concatMap freeVars (t:ts)
477 Type.RRecord fields ext ->
478 maybe [] freeVars ext
479 ++ 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