on 75ccf81 help sign in
elk/src/Validate.hs
450 lines 12 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2module Validate (declarations) where
4import Control.Applicative ((<$>),(<*>))
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
25declarations
26 :: Bool
27 -> [D.SourceDecl]
28 -> Result.Result wrn Error.Error [D.ValidDecl]
29declarations isRoot sourceDecls =
30 do validDecls <- validateDecls Nothing sourceDecls
31 (\_ _ -> validDecls)
32 <$> declDuplicates validDecls
33 <*> T.traverse (checkDecl isRoot) validDecls
36validateDecls
37 :: Maybe String
38 -> [D.SourceDecl]
39 -> Result.Result wrn Error.Error [D.ValidDecl]
40validateDecls maybeComment sourceDecls =
41 case sourceDecls of
42 [] ->
43 return []
45 sourceDecl : decls ->
46 case sourceDecl of
47 D.Comment comment ->
48 validateDecls (Just comment) decls
50 D.Decl decl ->
51 validateDeclsHelp maybeComment decl decls
54validateDeclsHelp
55 :: Maybe String
56 -> A.Located D.SourceDecl'
57 -> [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
63 in
64 case decl of
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)
74 D.Definition def ->
75 defHelp comment def decls
77 D.Port port ->
78 portHelp comment region port decls
81-- VALIDATE DEFINITIONS IN DECLARATIONS
83defHelp
84 :: Maybe String
85 -> Source.Def
86 -> [D.SourceDecl]
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
92 in
93 case def of
94 Source.Definition pat expr ->
95 do expr' <- expression expr
96 let def' = Valid.Definition pat expr' Nothing
97 checkDefinition def'
98 addRest def' decls
100 Source.TypeAnnotation name tipe ->
101 case decls of
102 D.Decl (A.A _ (D.Definition (A.A _
103 (Source.Definition pat@(A.A _ (Pattern.Var name')) expr)))) : rest
104 | name == name' ->
105 do expr' <- expression expr
106 let def' = Valid.Definition pat expr' (Just tipe)
107 checkDefinition def'
108 addRest def' rest
110 _ ->
111 Result.throw region (Error.TypeWithoutDefinition name)
114-- VALIDATE PORTS IN DECLARATIONS
116portHelp
117 :: Maybe String
118 -> R.Region
119 -> D.SourcePort
120 -> [D.SourceDecl]
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
126 in
127 case port of
128 D.PortDefinition name _ ->
129 Result.throw region (Error.PortWithoutAnnotation name)
131 D.PortAnnotation name tipe ->
132 case decls of
133 D.Decl (A.A _ (D.Port (D.PortDefinition name' expr))) : rest
134 | name == name' ->
135 do expr' <- expression expr
136 let port' = D.Out name expr' tipe
137 addRest port' rest
139 _ ->
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
150 return validDefs
153definitionsHelp :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
154definitionsHelp sourceDefs =
155 case sourceDefs of
156 [] ->
157 return []
159 A.A _ (Source.Definition pat expr) : rest ->
160 do expr' <- expression expr
161 let def = Valid.Definition pat expr' Nothing
162 checkDefinition def
163 (:) def <$> definitionsHelp rest
165 A.A region (Source.TypeAnnotation name tipe) : rest ->
166 case rest of
167 A.A _ (Source.Definition pat@(A.A _ (Pattern.Var name')) expr) : rest'
168 | name == name' ->
169 do expr' <- expression expr
170 let def = Valid.Definition pat expr' (Just tipe)
171 checkDefinition def
172 (:) def <$> definitionsHelp rest'
174 _ ->
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
181 [] ->
182 return ()
184 args ->
185 case pattern of
186 A.A _ (Pattern.Var _) ->
187 return ()
189 _ ->
190 let
191 (A.A start _) = pattern
192 (A.A end _) = last args
193 in
194 Result.throw (R.merge start end) (Error.BadFunctionName (length args))
197-- VALIDATE EXPRESSIONS
199expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
200expression (A.A ann sourceExpression) =
201 A.A ann <$>
202 case sourceExpression of
203 Var x ->
204 return (Var x)
206 Lambda pattern body ->
207 Lambda
208 <$> validatePattern pattern
209 <*> expression body
211 Binop op leftExpr rightExpr ->
212 Binop op
213 <$> expression leftExpr
214 <*> expression rightExpr
216 Case e branches ->
217 Case
218 <$> expression e
219 <*> T.traverse (\(p,b) -> (,) <$> validatePattern p <*> expression b) branches
221 Data name args ->
222 Data name <$> T.traverse expression args
224 Literal lit ->
225 return (Literal lit)
227 Range lowExpr highExpr ->
228 Range
229 <$> expression lowExpr
230 <*> expression highExpr
232 ExplicitList expressions ->
233 ExplicitList
234 <$> T.traverse expression expressions
236 App funcExpr argExpr ->
237 App
238 <$> expression funcExpr
239 <*> expression argExpr
241 If branches finally ->
242 If
243 <$> T.traverse both branches
244 <*> expression finally
246 Access record field ->
247 Access
248 <$> expression record
249 <*> return field
251 Update record fields ->
252 Update
253 <$> expression record
254 <*> T.traverse second fields
256 Record fields ->
257 Record
258 <$> T.traverse second fields
260 Let defs body ->
261 Let
262 <$> definitions defs
263 <*> expression body
265 GLShader uid src gltipe ->
266 return (GLShader uid src gltipe)
268 Port impl ->
269 Port <$>
270 case impl of
271 In name tipe ->
272 return (In name tipe)
274 Out name expr tipe ->
275 do expr' <- expression expr
276 return (Out name expr' tipe)
278 Task name expr tipe ->
279 do expr' <- expression expr
280 return (Task name expr' tipe)
283second :: (a, Source.Expr) -> Result.Result wrn Error.Error (a, Valid.Expr)
284second (value, expr) =
285 (,) value <$> expression expr
288both
289 :: (Source.Expr, Source.Expr)
290 -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
291both (expr1, expr2) =
292 (,) <$> expression expr1 <*> expression expr2
295-- VALIDATE PATTERNS
297validatePattern :: Pattern.RawPattern -> Result.Result wrn Error.Error Pattern.RawPattern
298validatePattern pattern =
299 do detectDuplicates Error.BadPattern (Pattern.boundVars pattern)
300 return pattern
303-- DETECT DUPLICATES
305detectDuplicates
306 :: (String -> Error.Error)
307 -> [A.Located String]
308 -> Result.Result wrn Error.Error ()
309detectDuplicates tag names =
310 let add (A.A region name) dict =
311 Map.insertWith (++) name [region] dict
313 makeGroups pairs =
314 Map.toList (foldr add Map.empty pairs)
316 check (name, regions) =
317 case regions of
318 _ : region : _ ->
319 Result.throw region (tag name)
321 _ ->
322 return ()
323 in
324 F.traverse_ check (makeGroups names)
327defDuplicates
328 :: [Pattern.RawPattern]
329 -> Result.Result wrn Error.Error ()
330defDuplicates patterns =
331 concatMap Pattern.boundVars patterns
332 |> detectDuplicates Error.DuplicateDefinition
335declDuplicates :: [D.ValidDecl] -> Result.Result wrn Error.Error ()
336declDuplicates decls =
337 let (valueLists, typeLists) = unzip (map extractValues decls)
338 in
339 (\_ _ -> ())
340 <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
341 <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
344extractValues :: D.ValidDecl -> ([A.Located String], [A.Located String])
345extractValues (A.A (region, _) decl) =
346 case decl of
347 D.Definition (Valid.Definition pattern _ _) ->
348 ( Pattern.boundVars pattern
349 , []
350 )
352 D.Datatype name _ ctors ->
353 ( map (A.A region . fst) ctors
354 , [A.A region name]
355 )
357 D.TypeAlias name _ (A.A _ (Type.RRecord _ _)) ->
358 ( [A.A region name]
359 , [A.A region name]
360 )
362 D.TypeAlias name _ _ ->
363 ( []
364 , [A.A region name]
365 )
367 D.Port port ->
368 ( [A.A region (D.validPortName port)]
369 , []
370 )
372 D.Fixity _ _ _ ->
373 ( []
374 , []
375 )
378-- UNBOUND TYPE VARIABLES
380checkDecl :: Bool -> D.ValidDecl -> Result.Result wrn Error.Error ()
381checkDecl isRoot (A.A (region,_) decl) =
382 case decl of
383 D.Definition _ ->
384 return ()
386 D.Datatype name boundVars ctors ->
387 let frees = concatMap freeVars (concatMap snd ctors)
388 in
389 case findUnbound boundVars frees of
390 [] ->
391 return ()
393 unbound ->
394 let
395 (v:vs) = Set.toList (Set.fromList unbound)
396 in
397 Result.throw region
398 (Error.UnboundTypeVarsInUnion name boundVars v vs ctors)
400 D.TypeAlias name boundVars tipe ->
401 case findUnbound boundVars (freeVars tipe) of
402 [] ->
403 return ()
405 unbound ->
406 let
407 (v:vs) = Set.toList (Set.fromList unbound)
408 in
409 Result.throw region
410 (Error.UnboundTypeVarsInAlias name boundVars v vs tipe)
412 D.Port _ ->
413 if isRoot
414 then return ()
415 else Result.throw region Error.UnexpectedPort
417 D.Fixity _ _ _ ->
418 return ()
421findUnbound :: [String] -> [A.Located String] -> [String]
422findUnbound boundVars frees =
423 let bounds = Set.fromList boundVars
425 isUnbound x =
426 Set.notMember x bounds
427 in
428 filter isUnbound (map A.drop frees)
432freeVars :: Type.Raw -> [A.Located String]
433freeVars (A.A region tipe) =
434 case tipe of
435 Type.RLambda t1 t2 ->
436 freeVars t1 ++ freeVars t2
438 Type.RVar x ->
439 [A.A region x]
441 Type.RType _ ->
442 []
444 Type.RApp t ts ->
445 concatMap freeVars (t:ts)
447 Type.RRecord fields ext ->
448 maybe [] freeVars ext
449 ++ concatMap (freeVars . snd) fields