1{-# OPTIONS_GHC -Wall #-}
2module Validate (declarations) where
4import Control.Monad (foldM)
5import qualified Data.Map as Map
6import qualified Data.Maybe as Maybe
7import qualified Data.Set as Set
8import qualified Data.Foldable as F
9import qualified Data.Traversable as T
11import AST.Expression.General as Expr
12import qualified AST.Expression.Source as Source
13import qualified AST.Expression.Valid as Valid
14import qualified AST.Declaration as D
15import qualified AST.Pattern as Pattern
16import qualified AST.Type as Type
17import Elm.Utils ((|>))
18import qualified Reporting.Annotation as A
19import qualified Reporting.Error.Syntax as Error
20import qualified Reporting.Region as R
21import qualified Reporting.Result as Result
29 A.Annotated (R.Region, Maybe (A.Located String)) a
33 :: [D.CommentOr (A.Located a)]
34 -> Result.Result wrn Error.Error [Commented a]
35collapseComments listWithComments =
36 case listWithComments of
40 D.Comment msg : D.Whatever (A.A region a) : rest ->
43 A.A (region, Just msg) a
45 fmap (entry:) (collapseComments rest)
47 D.Comment (A.A region _) : D.Comment _ : _ ->
48 Result.throw region Error.CommentOnComment
50 [D.Comment (A.A region _)] ->
51 Result.throw region Error.CommentOnNothing
53 D.Whatever (A.A region a) : rest ->
56 A.A (region, Nothing) a
58 fmap (entry:) (collapseComments rest)
65data StructuredSource =
67 { _decls :: [Commented D.Source']
68 , _cmds :: Maybe [Commented Source.Effect]
69 , _subs :: Maybe [Commented Source.Effect]
73extractEffects :: [Commented D.SourceOrDefine] -> Result.Result wrn Error.Error StructuredSource
74extractEffects commentedDecls =
75 case commentedDecls of
77 Result.ok (Src [] Nothing Nothing)
79 A.A ann (D.Source decl) : rest ->
80 do restSrc <- extractEffects rest
81 return $ restSrc { _decls = A.A ann decl : _decls restSrc }
83 A.A (region, _) (D.Define name commentOrEffects) : rest ->
84 do restSrc <- extractEffects rest
89 do effects <- collapseComments commentOrEffects
90 Result.ok $ restSrc { _cmds = Just effects }
93 Result.throw region (Error.DefineDuplicate name)
98 do effects <- collapseComments commentOrEffects
99 Result.ok $ restSrc { _subs = Just effects }
102 Result.throw region (Error.DefineDuplicate name)
105 Result.throw region (Error.DefineUnknown name)
109-- VALIDATE STRUCTURED SOURCE
112declarations :: [D.Source] -> Result.Result wrn Error.Error [D.Valid]
113declarations sourceDecls =
114 do (Src decls cmds subs) <-
115 extractEffects =<< collapseComments sourceDecls
121 validateEffects (Maybe.fromMaybe [] cmds)
124 validateEffects (Maybe.fromMaybe [] subs)
127 <$> declDuplicates validDecls
128 <*> T.traverse checkDecl validDecls
132-- VALIDATE DECLARATIONS
136 :: [Commented D.Source']
137 -> Result.Result wrn Error.Error [D.Valid]
138validateDecls commentedDecls =
139 case commentedDecls of
143 A.A (region, maybeComment) decl : rest ->
148 A.A (region, fmap A.drop maybeComment) validDecl
150 fmap (entry:) (validateDecls rest)
153 D.Union name tvars ctors ->
154 addRest (D.Union name tvars ctors)
156 D.Alias name tvars alias ->
157 addRest (D.Alias name tvars alias)
159 D.Fixity assoc prec op ->
160 addRest (D.Fixity assoc prec op)
163 validateDeclsHelp maybeComment def rest
167 :: Maybe (A.Located String)
169 -> [Commented D.Source']
170 -> Result.Result wrn Error.Error [D.Valid]
171validateDeclsHelp maybeComment (A.A region def) decls =
173 makeDef pat expr maybeType =
174 D.Def (Valid.Definition pat expr maybeType)
177 (region, fmap A.drop maybeComment)
180 Source.Definition pat expr ->
182 <$> validateDef makeDef ann pat expr Nothing
183 <*> validateDecls decls
185 Source.Annotation name tipe ->
187 A.A (_, Just (A.A commentRegion _)) _ : _ ->
188 Result.throw commentRegion (Error.CommentAfterAnnotation name)
190 A.A _ (D.Def (A.A _ (Source.Definition pat expr))) : rest
191 | Pattern.isVar name pat ->
193 <$> validateDef makeDef ann pat expr (Just tipe)
194 <*> validateDecls rest
197 Result.throw region (Error.TypeWithoutDefinition name)
205 :: [Commented Source.Effect]
206 -> Result.Result wrn Error.Error [A.Commented Valid.Effect]
207validateEffects effects =
212 A.A (region, maybeComment) effect : rest ->
213 validateEffectsHelp (region, fmap A.drop maybeComment) effect rest
217 :: (R.Region, Maybe String)
219 -> [Commented Source.Effect]
220 -> Result.Result wrn Error.Error [A.Commented Valid.Effect]
221validateEffectsHelp ann effect remainingEffects =
224 Result.throw (fst ann) (error "TODO")
226 Source.Def pat expr ->
228 <$> validateDef Valid.Def ann pat expr Nothing
229 <*> validateEffects remainingEffects
231 Source.Type name tipe ->
232 case remainingEffects of
233 A.A (_, Just (A.A commentRegion _)) _ : _ ->
234 Result.throw commentRegion (Error.CommentAfterAnnotation name)
236 A.A _ (Source.Def pat expr) : rest
237 | Pattern.isVar name pat ->
239 <$> validateDef Valid.Def ann pat expr (Just tipe)
240 <*> validateEffects rest
243 Result.throw (fst ann) (Error.TypeWithoutDefinition name)
247-- VALIDATE DEFINITIONS
250definitions :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
251definitions sourceDefs =
252 do validDefs <- definitionsHelp sourceDefs
253 let patterns = map (\(Valid.Definition p _ _) -> p) validDefs
254 defDuplicates patterns
258definitionsHelp :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
259definitionsHelp sourceDefs =
264 A.A region (Source.Definition pat expr) : rest ->
266 <$> fmap A.drop (validateDef Valid.Definition region pat expr Nothing)
267 <*> definitionsHelp rest
269 A.A r1 (Source.Annotation name tipe) : rest ->
271 A.A r2 (Source.Definition pat expr) : rest'
272 | Pattern.isVar name pat ->
274 <$> fmap A.drop (validateDef Valid.Definition (R.merge r1 r2) pat expr (Just tipe))
275 <*> definitionsHelp rest'
278 Result.throw r1 (Error.TypeWithoutDefinition name)
282 :: (Pattern.Raw -> Valid.Expr -> Maybe Type.Raw -> def)
287 -> Result.Result wrn Error.Error (A.Annotated annotation def)
288validateDef makeDef annotation pat expr maybeType =
289 do validExpr <- expression expr
290 validateDefPattern pat validExpr
291 return $ A.A annotation (makeDef pat validExpr maybeType)
294validateDefPattern :: Pattern.Raw -> Valid.Expr -> Result.Result wrn Error.Error ()
295validateDefPattern pattern body =
296 case fst (Expr.collectLambdas body) of
302 A.A _ (Pattern.Var _) ->
307 (A.A start _) = pattern
308 (A.A end _) = last args
310 Result.throw (R.merge start end) (Error.BadFunctionName (length args))
314-- VALIDATE EXPRESSIONS
317expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
318expression (A.A ann sourceExpression) =
320 case sourceExpression of
324 Lambda pattern body ->
326 <$> validatePattern pattern
329 Binop op leftExpr rightExpr ->
331 <$> expression leftExpr
332 <*> expression rightExpr
337 <*> T.traverse (\(p,b) -> (,) <$> validatePattern p <*> expression b) branches
340 Data name <$> T.traverse expression args
345 Range lowExpr highExpr ->
347 <$> expression lowExpr
348 <*> expression highExpr
350 ExplicitList expressions ->
352 <$> T.traverse expression expressions
354 App funcExpr argExpr ->
356 <$> expression funcExpr
357 <*> expression argExpr
359 If branches finally ->
361 <$> T.traverse both branches
362 <*> expression finally
364 Access record field ->
366 <$> expression record
369 Update record fields ->
371 <$> expression record
372 <*> T.traverse second fields
376 checkDups seenFields (field,_) =
377 if Set.member field seenFields then
378 Result.throw ann (Error.DuplicateFieldName field)
381 return (Set.insert field seenFields)
383 do _ <- foldM checkDups Set.empty fields
384 Record <$> T.traverse second fields
391 GLShader uid src gltipe ->
392 return (GLShader uid src gltipe)
395second :: (a, Source.Expr) -> Result.Result wrn Error.Error (a, Valid.Expr)
396second (value, expr) =
397 (,) value <$> expression expr
401 :: (Source.Expr, Source.Expr)
402 -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
404 (,) <$> expression expr1 <*> expression expr2
411validatePattern :: Pattern.Raw -> Result.Result wrn Error.Error Pattern.Raw
412validatePattern pattern =
413 do detectDuplicates Error.BadPattern (Pattern.boundVars pattern)
422 :: (String -> Error.Error)
423 -> [A.Located String]
424 -> Result.Result wrn Error.Error ()
425detectDuplicates tag names =
426 let add (A.A region name) dict =
427 Map.insertWith (++) name [region] dict
430 Map.toList (foldr add Map.empty pairs)
432 check (name, regions) =
435 Result.throw region (tag name)
440 F.traverse_ check (makeGroups names)
443defDuplicates :: [Pattern.Raw] -> Result.Result wrn Error.Error ()
444defDuplicates patterns =
445 concatMap Pattern.boundVars patterns
446 |> detectDuplicates Error.DuplicateDefinition
449declDuplicates :: [D.Valid] -> Result.Result wrn Error.Error ()
450declDuplicates decls =
451 let (valueLists, typeLists) = unzip (map extractValues decls)
454 <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
455 <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
458extractValues :: D.Valid -> ([A.Located String], [A.Located String])
459extractValues (A.A (region, _) decl) =
461 D.Def (Valid.Definition pattern _ _) ->
462 ( Pattern.boundVars pattern
466 D.Union name _ ctors ->
467 ( map (A.A region . fst) ctors
471 D.Alias name _ (A.A _ (Type.RRecord _ _)) ->
488-- UNBOUND TYPE VARIABLES
491checkDecl :: D.Valid -> Result.Result wrn Error.Error ()
492checkDecl (A.A (region,_) decl) =
497 D.Union name boundVars ctors ->
498 case diff boundVars (concatMap freeVars (concatMap snd ctors)) of
504 (Error.UnboundTypeVarsInUnion name boundVars unbound)
506 D.Alias name boundVars tipe ->
507 case diff boundVars (freeVars tipe) of
513 (Error.UnboundTypeVarsInAlias name boundVars unbound)
517 (Error.UnusedTypeVarsInAlias name boundVars unused)
521 (Error.MessyTypeVarsInAlias name boundVars unused unbound)
527diff :: [String] -> [A.Located String] -> ([String], [String])
534 Set.fromList (map A.drop right)
536 ( Set.toList (Set.difference leftSet rightSet)
537 , Set.toList (Set.difference rightSet leftSet)
542freeVars :: Type.Raw -> [A.Located String]
543freeVars (A.A region tipe) =
545 Type.RLambda t1 t2 ->
546 freeVars t1 ++ freeVars t2
555 concatMap freeVars (t:ts)
557 Type.RRecord fields ext ->
558 maybe [] freeVars ext
559 ++ 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