1{-# OPTIONS_GHC -Wall #-}
2module Validate (declarations) where
4import qualified Control.Arrow as Arrow
5import Control.Monad (foldM)
6import qualified Data.Map as Map
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.Module as Module
16import qualified AST.Pattern as Pattern
17import qualified AST.Type as Type
18import Elm.Utils ((|>))
19import qualified Reporting.Annotation as A
20import qualified Reporting.Error.Syntax as Error
21import qualified Reporting.Region as R
22import qualified Reporting.Result as Result
30 A.Annotated (R.Region, Maybe (A.Located String)) a
34 :: [D.CommentOr (A.Located a)]
35 -> Result.Result wrn Error.Error [Commented a]
36collapseComments listWithComments =
37 case listWithComments of
41 D.Comment msg : D.Whatever (A.A region a) : rest ->
44 A.A (region, Just msg) a
46 fmap (entry:) (collapseComments rest)
48 D.Comment (A.A region _) : D.Comment _ : _ ->
49 Result.throw region Error.CommentOnComment
51 [D.Comment (A.A region _)] ->
52 Result.throw region Error.CommentOnNothing
54 D.Whatever (A.A region a) : rest ->
57 A.A (region, Nothing) a
59 fmap (entry:) (collapseComments rest)
63-- PARTITION AND VALIDATE DEFINES
67 Map.Map D.EffectType [A.Located [D.CommentOr (A.Located Source.Effect)]]
70partitionEffects :: [Commented D.SourceOrDefine] -> ([Commented D.Source'], Defines)
71partitionEffects commentedDecls =
72 case commentedDecls of
76 A.A ann (D.Source decl) : rest ->
79 (partitionEffects rest)
81 A.A (region, _) (D.Define effectType commentOrEffects) : rest ->
83 (Map.insertWith (++) effectType [A.A region commentOrEffects])
84 (partitionEffects rest)
90 -> Result.Result wrn Error.Error Valid.Effects
91validateDefines tag defines =
94 do disallowLeftoverDefines Error.BadDefineInNormalModule defines
97 Module.Effect region ->
99 (maybeCmds, smallerDefines) =
100 extractKey D.Cmd defines
102 (maybeSubs, leftovers) =
103 extractKey D.Sub smallerDefines
105 do disallowLeftoverDefines Error.BadDefineInEffectModule leftovers
106 case (maybeCmds, maybeSubs) of
107 (Nothing, Nothing) ->
108 Result.throw region Error.NoDefineInEffectModule
113 <$> validateDefineDefs D.Cmd maybeCmds validateEffects
114 <*> validateDefineDefs D.Sub maybeSubs validateEffects
116 Module.Foreign region ->
118 (maybeCmds, smallerDefines) =
119 extractKey D.ForeignCmd defines
121 (maybeSubs, leftovers) =
122 extractKey D.ForeignSub smallerDefines
124 do disallowLeftoverDefines Error.BadDefineInForeignModule leftovers
125 case (maybeCmds, maybeSubs) of
126 (Nothing, Nothing) ->
127 Result.throw region Error.NoDefineInForeignModule
131 <$> validateDefineDefs D.ForeignCmd maybeCmds (T.traverse validateForeignCmd)
132 <*> validateDefineDefs D.ForeignSub maybeSubs (T.traverse validateForeignSub)
135extractKey :: (Ord k) => k -> Map.Map k v -> (Maybe v, Map.Map k v)
137 ( Map.lookup key dict
138 , Map.delete key dict
144 -> Maybe [A.Located [D.CommentOr (A.Located Source.Effect)]]
145 -> ([Commented Source.Effect] -> Result.Result wrn Error.Error a)
146 -> Result.Result wrn Error.Error a
147validateDefineDefs effectType maybeAllRawDefines validate =
148 case maybeAllRawDefines of
152 Just [A.A _ sourceDefs] ->
153 validate =<< collapseComments sourceDefs
155 Just allRawDefines ->
161 Error.DuplicateDefines effectType (length allRawDefines)
163 Result.throw region errorMsg
166disallowLeftoverDefines
167 :: (D.EffectType -> Error.Error)
169 -> Result.Result wrn Error.Error ()
170disallowLeftoverDefines errorTagger leftoverDefines =
171 case Map.toList leftoverDefines of
177 toErrors (key, allDefines) =
178 map (A.map (\_ -> errorTagger key)) allDefines
180 Result.throwMany (concatMap toErrors pairs)
184-- VALIDATE STRUCTURED SOURCE
190 -> Result.Result wrn Error.Error ([D.Valid], Valid.Effects)
191declarations tag sourceDecls =
192 do (decls, defines) <-
193 partitionEffects <$> collapseComments sourceDecls
199 validateDefines tag defines
202 (declDuplicates validDecls validEffects : map findBadTypeVars validDecls)
204 return (validDecls, validEffects)
208-- VALIDATE DECLARATIONS
212 :: [Commented D.Source']
213 -> Result.Result wrn Error.Error [D.Valid]
214validateDecls commentedDecls =
215 case commentedDecls of
219 A.A (region, maybeComment) decl : rest ->
224 A.A (region, fmap A.drop maybeComment) validDecl
226 fmap (entry:) (validateDecls rest)
229 D.Union name tvars ctors ->
230 addRest (D.Union name tvars ctors)
232 D.Alias name tvars alias ->
233 addRest (D.Alias name tvars alias)
235 D.Fixity assoc prec op ->
236 addRest (D.Fixity assoc prec op)
239 validateDeclsHelp maybeComment def rest
243 :: Maybe (A.Located String)
245 -> [Commented D.Source']
246 -> Result.Result wrn Error.Error [D.Valid]
247validateDeclsHelp maybeComment (A.A region def) decls =
250 (region, fmap A.drop maybeComment)
252 makeDef pat expr maybeType =
253 D.Def (Valid.Definition pat expr maybeType)
256 Source.Definition pat expr ->
258 <$> validateDef makeDef ann pat expr Nothing
259 <*> validateDecls decls
261 Source.Annotation name tipe ->
263 A.A (_, Just (A.A commentRegion _)) _ : _ ->
264 Result.throw commentRegion (Error.CommentAfterAnnotation name)
266 A.A _ (D.Def (A.A _ (Source.Definition pat expr))) : rest
267 | Pattern.isVar name pat ->
269 <$> validateDef makeDef ann pat expr (Just tipe)
270 <*> validateDecls rest
273 Result.throw region (Error.TypeWithoutDefinition name)
281 :: [Commented Source.Effect]
282 -> Result.Result wrn Error.Error [A.Commented Valid.Def]
283validateEffects effects =
288 A.A (region, maybeComment) effect : rest ->
289 validateEffectsHelp (region, fmap A.drop maybeComment) effect rest
293 :: (R.Region, Maybe String)
295 -> [Commented Source.Effect]
296 -> Result.Result wrn Error.Error [A.Commented Valid.Def]
297validateEffectsHelp ann effect remainingEffects =
300 Result.throw (fst ann) (error "TODO")
302 Source.Def pat expr ->
304 <$> validateDef Valid.Definition ann pat expr Nothing
305 <*> validateEffects remainingEffects
307 Source.Type name tipe ->
308 case remainingEffects of
309 A.A (_, Just (A.A commentRegion _)) _ : _ ->
310 Result.throw commentRegion (Error.CommentAfterAnnotation name)
312 A.A _ (Source.Def pat expr) : rest
313 | Pattern.isVar name pat ->
315 <$> validateDef Valid.Definition ann pat expr (Just tipe)
316 <*> validateEffects rest
319 Result.throw (fst ann) (Error.TypeWithoutDefinition name)
323 :: Commented Source.Effect
324 -> Result.Result wrn Error.Error (A.Commented Valid.ForeignCmd)
325validateForeignCmd (A.A (region, maybeComment) effect) =
328 Result.throw region (error "TODO")
331 Result.throw region (error "TODO")
333 Source.Type name tipe ->
335 A.A (region, fmap A.drop maybeComment) (Valid.Cmd name tipe)
339 :: Commented Source.Effect
340 -> Result.Result wrn Error.Error (A.Commented Valid.ForeignSub)
341validateForeignSub (A.A (region, maybeComment) effect) =
343 Source.With name expr ->
344 do validExpr <- expression expr
346 A.A (region, fmap A.drop maybeComment) (Valid.SubWith name validExpr)
349 Result.throw region (error "TODO")
351 Source.Type name tipe ->
353 A.A (region, fmap A.drop maybeComment) (Valid.Sub name tipe)
357-- VALIDATE DEFINITIONS
360definitions :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
361definitions sourceDefs =
362 do validDefs <- definitionsHelp sourceDefs
363 let patterns = map (\(Valid.Definition p _ _) -> p) validDefs
364 defDuplicates patterns
368definitionsHelp :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
369definitionsHelp sourceDefs =
374 A.A region (Source.Definition pat expr) : rest ->
376 <$> fmap A.drop (validateDef Valid.Definition region pat expr Nothing)
377 <*> definitionsHelp rest
379 A.A r1 (Source.Annotation name tipe) : rest ->
381 A.A r2 (Source.Definition pat expr) : rest'
382 | Pattern.isVar name pat ->
384 <$> fmap A.drop (validateDef Valid.Definition (R.merge r1 r2) pat expr (Just tipe))
385 <*> definitionsHelp rest'
388 Result.throw r1 (Error.TypeWithoutDefinition name)
392 :: (Pattern.Raw -> Valid.Expr -> Maybe Type.Raw -> def)
397 -> Result.Result wrn Error.Error (A.Annotated annotation def)
398validateDef makeDef annotation pat expr maybeType =
399 do validExpr <- expression expr
400 validateDefPattern pat validExpr
401 return $ A.A annotation (makeDef pat validExpr maybeType)
404validateDefPattern :: Pattern.Raw -> Valid.Expr -> Result.Result wrn Error.Error ()
405validateDefPattern pattern body =
406 case fst (Expr.collectLambdas body) of
412 A.A _ (Pattern.Var _) ->
417 (A.A start _) = pattern
418 (A.A end _) = last args
420 Result.throw (R.merge start end) (Error.BadFunctionName (length args))
424-- VALIDATE EXPRESSIONS
427expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
428expression (A.A ann sourceExpression) =
430 case sourceExpression of
434 Lambda pattern body ->
436 <$> validatePattern pattern
439 Binop op leftExpr rightExpr ->
441 <$> expression leftExpr
442 <*> expression rightExpr
447 <*> T.traverse (\(p,b) -> (,) <$> validatePattern p <*> expression b) branches
450 Data name <$> T.traverse expression args
455 Range lowExpr highExpr ->
457 <$> expression lowExpr
458 <*> expression highExpr
460 ExplicitList expressions ->
462 <$> T.traverse expression expressions
464 App funcExpr argExpr ->
466 <$> expression funcExpr
467 <*> expression argExpr
469 If branches finally ->
471 <$> T.traverse both branches
472 <*> expression finally
474 Access record field ->
476 <$> expression record
479 Update record fields ->
481 <$> expression record
482 <*> T.traverse second fields
486 checkDups seenFields (field,_) =
487 if Set.member field seenFields then
488 Result.throw ann (Error.DuplicateFieldName field)
491 return (Set.insert field seenFields)
493 do _ <- foldM checkDups Set.empty fields
494 Record <$> T.traverse second fields
501 GLShader uid src gltipe ->
502 return (GLShader uid src gltipe)
505second :: (a, Source.Expr) -> Result.Result wrn Error.Error (a, Valid.Expr)
506second (value, expr) =
507 (,) value <$> expression expr
511 :: (Source.Expr, Source.Expr)
512 -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
514 (,) <$> expression expr1 <*> expression expr2
521validatePattern :: Pattern.Raw -> Result.Result wrn Error.Error Pattern.Raw
522validatePattern pattern =
523 do detectDuplicates Error.BadPattern (Pattern.boundVars pattern)
532 :: (String -> Error.Error)
533 -> [A.Located String]
534 -> Result.Result wrn Error.Error ()
535detectDuplicates tag names =
536 let add (A.A region name) dict =
537 Map.insertWith (++) name [region] dict
540 Map.toList (foldr add Map.empty pairs)
542 check (name, regions) =
545 Result.throw region (tag name)
550 F.traverse_ check (makeGroups names)
553defDuplicates :: [Pattern.Raw] -> Result.Result wrn Error.Error ()
554defDuplicates patterns =
555 concatMap Pattern.boundVars patterns
556 |> detectDuplicates Error.DuplicateDefinition
559declDuplicates :: [D.Valid] -> Valid.Effects -> Result.Result wrn Error.Error ()
560declDuplicates decls effects =
562 (valueLists, typeLists) =
563 unzip (map extractValues decls)
566 extractEffectValues effects
569 <$> detectDuplicates Error.DuplicateValueDeclaration (effectValues ++ concat valueLists)
570 <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
573extractValues :: D.Valid -> ([A.Located String], [A.Located String])
574extractValues (A.A (region, _) decl) =
576 D.Def (Valid.Definition pattern _ _) ->
577 ( Pattern.boundVars pattern
581 D.Union name _ ctors ->
582 ( map (A.A region . fst) ctors
586 D.Alias name _ (A.A _ (Type.RRecord _ _)) ->
602extractEffectValues :: Valid.Effects -> [A.Located String]
603extractEffectValues effects =
608 Valid.Effects cmds subs ->
610 extractNames (Valid.Definition pat _ _) =
611 Pattern.boundVars pat
613 concatMap (extractNames . A.drop) (cmds ++ subs)
615 Valid.ForeignEffects cmds subs ->
617 extractCmdNames (A.A (region, _) (Valid.Cmd name _)) =
620 extractSubNames (A.A (region, _) sub) =
626 Valid.SubWith name _ ->
629 map extractCmdNames cmds ++ map extractSubNames subs
633-- UNBOUND TYPE VARIABLES
636findBadTypeVars :: D.Valid -> Result.Result wrn Error.Error ()
637findBadTypeVars (A.A (region,_) decl) =
642 D.Union name boundVars ctors ->
643 case diff boundVars (concatMap freeVars (concatMap snd ctors)) of
649 (Error.UnboundTypeVarsInUnion name boundVars unbound)
651 D.Alias name boundVars tipe ->
652 case diff boundVars (freeVars tipe) of
658 (Error.UnboundTypeVarsInAlias name boundVars unbound)
662 (Error.UnusedTypeVarsInAlias name boundVars unused)
666 (Error.MessyTypeVarsInAlias name boundVars unused unbound)
672diff :: [String] -> [A.Located String] -> ([String], [String])
679 Set.fromList (map A.drop right)
681 ( Set.toList (Set.difference leftSet rightSet)
682 , Set.toList (Set.difference rightSet leftSet)
687freeVars :: Type.Raw -> [A.Located String]
688freeVars (A.A region tipe) =
690 Type.RLambda t1 t2 ->
691 freeVars t1 ++ freeVars t2
700 concatMap freeVars (t:ts)
702 Type.RRecord fields ext ->
703 maybe [] freeVars ext
704 ++ 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