1{-# OPTIONS_GHC -Wall #-}
2module Validate (declarations) where
4import qualified Data.Map as Map
5import qualified Data.Set as Set
6import qualified Data.Foldable as F
7import qualified Data.Traversable as T
9import AST.Expression.General as Expr
10import qualified AST.Expression.Source as Source
11import qualified AST.Expression.Valid as Valid
12import qualified AST.Declaration as D
13import qualified AST.Pattern as Pattern
14import qualified AST.Type as Type
15import Elm.Utils ((|>))
16import qualified Reporting.Annotation as A
17import qualified Reporting.Error.Syntax as Error
18import qualified Reporting.Region as R
19import qualified Reporting.Result as Result
22-- VALIDATE DECLARATIONS
27 -> Result.Result wrn Error.Error [D.ValidDecl]
28declarations isRoot sourceDecls =
29 do validDecls <- validateDecls Nothing sourceDecls
31 <$> declDuplicates validDecls
32 <*> T.traverse (checkDecl isRoot) validDecls
38 -> Result.Result wrn Error.Error [D.ValidDecl]
39validateDecls maybeComment sourceDecls =
47 validateDecls (Just comment) decls
50 validateDeclsHelp maybeComment decl decls
55 -> A.Located D.SourceDecl'
57 -> Result.Result wrn Error.Error [D.ValidDecl]
58validateDeclsHelp comment (A.A region decl) decls =
59 let addRest validDecl =
60 (:) (A.A (region, comment) validDecl)
61 <$> validateDecls Nothing decls
64 D.Datatype name tvars ctors ->
65 addRest (D.Datatype name tvars ctors)
67 D.TypeAlias name tvars alias ->
68 addRest (D.TypeAlias name tvars alias)
70 D.Fixity assoc prec op ->
71 addRest (D.Fixity assoc prec op)
74 defHelp comment def decls
77 portHelp comment region port decls
80-- VALIDATE DEFINITIONS IN DECLARATIONS
86 -> Result.Result wrn Error.Error [D.ValidDecl]
87defHelp comment (A.A region def) decls =
88 let addRest def' rest =
89 (:) (A.A (region, comment) (D.Definition def'))
90 <$> validateDecls Nothing rest
93 Source.Definition pat expr ->
94 do expr' <- expression expr
95 let def' = Valid.Definition pat expr' Nothing
99 Source.TypeAnnotation name tipe ->
101 D.Decl (A.A _ (D.Definition (A.A _
102 (Source.Definition pat@(A.A _ (Pattern.Var name')) expr)))) : rest
104 do expr' <- expression expr
105 let def' = Valid.Definition pat expr' (Just tipe)
110 Result.throw region (Error.TypeWithoutDefinition name)
113-- VALIDATE PORTS IN DECLARATIONS
120 -> Result.Result wrn Error.Error [D.ValidDecl]
121portHelp comment region port decls =
122 let addRest port' rest =
123 (:) (A.A (region,comment) (D.Port port'))
124 <$> validateDecls Nothing rest
127 D.PortDefinition name _ ->
128 Result.throw region (Error.PortWithoutAnnotation name)
130 D.PortAnnotation name tipe ->
132 D.Decl (A.A _ (D.Port (D.PortDefinition name' expr))) : rest
134 do expr' <- expression expr
135 let port' = D.Out name expr' tipe
139 addRest (D.In name tipe) decls
142-- VALIDATE DEFINITIONS
144definitions :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
145definitions sourceDefs =
146 do validDefs <- definitionsHelp sourceDefs
147 let patterns = map (\(Valid.Definition p _ _) -> p) validDefs
148 defDuplicates patterns
152definitionsHelp :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
153definitionsHelp sourceDefs =
158 A.A _ (Source.Definition pat expr) : rest ->
159 do expr' <- expression expr
160 let def = Valid.Definition pat expr' Nothing
162 (:) def <$> definitionsHelp rest
164 A.A region (Source.TypeAnnotation name tipe) : rest ->
166 A.A _ (Source.Definition pat@(A.A _ (Pattern.Var name')) expr) : rest'
168 do expr' <- expression expr
169 let def = Valid.Definition pat expr' (Just tipe)
171 (:) def <$> definitionsHelp rest'
174 Result.throw region (Error.TypeWithoutDefinition name)
177checkDefinition :: Valid.Def -> Result.Result wrn Error.Error ()
178checkDefinition (Valid.Definition pattern body _) =
179 case fst (Expr.collectLambdas body) of
185 A.A _ (Pattern.Var _) ->
190 (A.A start _) = pattern
191 (A.A end _) = last args
193 Result.throw (R.merge start end) (Error.BadFunctionName (length args))
196-- VALIDATE EXPRESSIONS
198expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
199expression (A.A ann sourceExpression) =
201 case sourceExpression of
205 Lambda pattern body ->
207 <$> validatePattern pattern
210 Binop op leftExpr rightExpr ->
212 <$> expression leftExpr
213 <*> expression rightExpr
218 <*> T.traverse (\(p,b) -> (,) <$> validatePattern p <*> expression b) branches
221 Data name <$> T.traverse expression args
226 Range lowExpr highExpr ->
228 <$> expression lowExpr
229 <*> expression highExpr
231 ExplicitList expressions ->
233 <$> T.traverse expression expressions
235 App funcExpr argExpr ->
237 <$> expression funcExpr
238 <*> expression argExpr
240 If branches finally ->
242 <$> T.traverse both branches
243 <*> expression finally
245 Access record field ->
247 <$> expression record
250 Update record fields ->
252 <$> expression record
253 <*> T.traverse second fields
257 <$> T.traverse second fields
264 GLShader uid src gltipe ->
265 return (GLShader uid src gltipe)
271 return (In name tipe)
273 Out name expr tipe ->
274 do expr' <- expression expr
275 return (Out name expr' tipe)
277 Task name expr tipe ->
278 do expr' <- expression expr
279 return (Task name expr' tipe)
282second :: (a, Source.Expr) -> Result.Result wrn Error.Error (a, Valid.Expr)
283second (value, expr) =
284 (,) value <$> expression expr
288 :: (Source.Expr, Source.Expr)
289 -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
291 (,) <$> expression expr1 <*> expression expr2
296validatePattern :: Pattern.RawPattern -> Result.Result wrn Error.Error Pattern.RawPattern
297validatePattern pattern =
298 do detectDuplicates Error.BadPattern (Pattern.boundVars pattern)
305 :: (String -> Error.Error)
306 -> [A.Located String]
307 -> Result.Result wrn Error.Error ()
308detectDuplicates tag names =
309 let add (A.A region name) dict =
310 Map.insertWith (++) name [region] dict
313 Map.toList (foldr add Map.empty pairs)
315 check (name, regions) =
318 Result.throw region (tag name)
323 F.traverse_ check (makeGroups names)
327 :: [Pattern.RawPattern]
328 -> Result.Result wrn Error.Error ()
329defDuplicates patterns =
330 concatMap Pattern.boundVars patterns
331 |> detectDuplicates Error.DuplicateDefinition
334declDuplicates :: [D.ValidDecl] -> Result.Result wrn Error.Error ()
335declDuplicates decls =
336 let (valueLists, typeLists) = unzip (map extractValues decls)
339 <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
340 <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
343extractValues :: D.ValidDecl -> ([A.Located String], [A.Located String])
344extractValues (A.A (region, _) decl) =
346 D.Definition (Valid.Definition pattern _ _) ->
347 ( Pattern.boundVars pattern
351 D.Datatype name _ ctors ->
352 ( map (A.A region . fst) ctors
356 D.TypeAlias name _ (A.A _ (Type.RRecord _ _)) ->
361 D.TypeAlias name _ _ ->
367 ( [A.A region (D.validPortName port)]
377-- UNBOUND TYPE VARIABLES
379checkDecl :: Bool -> D.ValidDecl -> Result.Result wrn Error.Error ()
380checkDecl isRoot (A.A (region,_) decl) =
385 D.Datatype name boundVars ctors ->
386 let frees = concatMap freeVars (concatMap snd ctors)
388 case findUnbound boundVars frees of
394 (v:vs) = Set.toList (Set.fromList unbound)
397 (Error.UnboundTypeVarsInUnion name boundVars v vs ctors)
399 D.TypeAlias name boundVars tipe ->
400 case findUnbound boundVars (freeVars tipe) of
406 (v:vs) = Set.toList (Set.fromList unbound)
409 (Error.UnboundTypeVarsInAlias name boundVars v vs tipe)
414 else Result.throw region Error.UnexpectedPort
420findUnbound :: [String] -> [A.Located String] -> [String]
421findUnbound boundVars frees =
422 let bounds = Set.fromList boundVars
425 Set.notMember x bounds
427 filter isUnbound (map A.drop frees)
431freeVars :: Type.Raw -> [A.Located String]
432freeVars (A.A region tipe) =
434 Type.RLambda t1 t2 ->
435 freeVars t1 ++ freeVars t2
444 concatMap freeVars (t:ts)
446 Type.RRecord fields ext ->
447 maybe [] freeVars ext
448 ++ 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