on ed48cd2 help sign in
elk/src/Validate.hs
426 lines 11 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
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' <- Validate.expression expr
96 let def' = Valid.Definition pat expr' Nothing
97 addRest def' decls
99 Source.TypeAnnotation name tipe ->
100 case decls of
101 D.Decl (A.A _ (D.Definition (A.A _
102 (Source.Definition pat@(A.A _ (Pattern.Var name')) expr)))) : rest
103 | name == name' ->
104 do expr' <- Validate.expression expr
105 let def' = Valid.Definition pat expr' (Just tipe)
106 addRest def' rest
108 _ ->
109 Result.throw region (Error.TypeWithoutDefinition name)
112-- VALIDATE PORTS IN DECLARATIONS
114portHelp
115 :: Maybe String
116 -> R.Region
117 -> D.SourcePort
118 -> [D.SourceDecl]
119 -> Result.Result wrn Error.Error [D.ValidDecl]
120portHelp comment region port decls =
121 let addRest port' rest =
122 (:) (A.A (region,comment) (D.Port port'))
123 <$> validateDecls Nothing rest
124 in
125 case port of
126 D.PortDefinition name _ ->
127 Result.throw region (Error.PortWithoutAnnotation name)
129 D.PortAnnotation name tipe ->
130 case decls of
131 D.Decl (A.A _ (D.Port (D.PortDefinition name' expr))) : rest
132 | name == name' ->
133 do expr' <- Validate.expression expr
134 let port' = D.Out name expr' tipe
135 addRest port' rest
137 _ ->
138 addRest (D.In name tipe) decls
141-- VALIDATE DEFINITIONS
143definitions :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
144definitions sourceDefs =
145 do validDefs <- definitionsHelp sourceDefs
146 let patterns = map (\(Valid.Definition p _ _) -> p) validDefs
147 defDuplicates patterns
148 return validDefs
151definitionsHelp :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
152definitionsHelp sourceDefs =
153 case sourceDefs of
154 [] ->
155 return []
157 A.A _ (Source.Definition pat expr) : rest ->
158 do expr' <- expression expr
159 let def = Valid.Definition pat expr' Nothing
160 (:) def <$> definitionsHelp rest
162 A.A region (Source.TypeAnnotation name tipe) : rest ->
163 case rest of
164 A.A _ (Source.Definition pat@(A.A _ (Pattern.Var name')) expr) : rest'
165 | name == name' ->
166 do expr' <- expression expr
167 let def = Valid.Definition pat expr' (Just tipe)
168 (:) def <$> definitionsHelp rest'
170 _ ->
171 Result.throw region (Error.TypeWithoutDefinition name)
174-- VALIDATE EXPRESSIONS
176expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
177expression (A.A ann sourceExpression) =
178 A.A ann <$>
179 case sourceExpression of
180 Var x ->
181 return (Var x)
183 Lambda pattern body ->
184 Lambda pattern <$> expression body
186 Binop op leftExpr rightExpr ->
187 Binop op
188 <$> expression leftExpr
189 <*> expression rightExpr
191 Case e branches ->
192 Case
193 <$> expression e
194 <*> T.traverse second branches
196 Data name args ->
197 Data name <$> T.traverse expression args
199 Literal lit ->
200 return (Literal lit)
202 Range lowExpr highExpr ->
203 Range
204 <$> expression lowExpr
205 <*> expression highExpr
207 ExplicitList expressions ->
208 ExplicitList
209 <$> T.traverse expression expressions
211 App funcExpr argExpr ->
212 App
213 <$> expression funcExpr
214 <*> expression argExpr
216 MultiIf branches ->
217 MultiIf <$> T.traverse both branches
219 Access record field ->
220 Access
221 <$> expression record
222 <*> return field
224 Remove record field ->
225 Remove
226 <$> expression record
227 <*> return field
229 Insert record field expr ->
230 Insert
231 <$> expression record
232 <*> return field
233 <*> expression expr
235 Modify record fields ->
236 Modify
237 <$> expression record
238 <*> T.traverse second fields
240 Record fields ->
241 Record
242 <$> T.traverse second fields
244 Let defs body ->
245 Let
246 <$> definitions defs
247 <*> expression body
249 GLShader uid src gltipe ->
250 return (GLShader uid src gltipe)
252 Port impl ->
253 Port <$>
254 case impl of
255 In name tipe ->
256 return (In name tipe)
258 Out name expr tipe ->
259 do expr' <- expression expr
260 return (Out name expr' tipe)
262 Task name expr tipe ->
263 do expr' <- expression expr
264 return (Task name expr' tipe)
267second :: (a, Source.Expr) -> Result.Result wrn Error.Error (a, Valid.Expr)
268second (value, expr) =
269 (,) value <$> expression expr
272both
273 :: (Source.Expr, Source.Expr)
274 -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
275both (expr1, expr2) =
276 (,) <$> expression expr1 <*> expression expr2
279-- DETECT DUPLICATES
281detectDuplicates
282 :: (String -> Error.Error)
283 -> [A.Located String]
284 -> Result.Result wrn Error.Error ()
285detectDuplicates tag names =
286 let add (A.A region name) dict =
287 Map.insertWith (++) name [region] dict
289 makeGroups pairs =
290 Map.toList (foldr add Map.empty pairs)
292 check (name, regions) =
293 case regions of
294 _ : region : _ ->
295 Result.throw region (tag name)
297 _ ->
298 return ()
299 in
300 F.traverse_ check (makeGroups names)
303defDuplicates
304 :: [Pattern.RawPattern]
305 -> Result.Result wrn Error.Error ()
306defDuplicates patterns =
307 concatMap Pattern.boundVars patterns
308 |> detectDuplicates Error.DuplicateDefinition
311declDuplicates :: [D.ValidDecl] -> Result.Result wrn Error.Error ()
312declDuplicates decls =
313 let (valueLists, typeLists) = unzip (map extractValues decls)
314 in
315 (\_ _ -> ())
316 <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
317 <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
320extractValues :: D.ValidDecl -> ([A.Located String], [A.Located String])
321extractValues (A.A (region, _) decl) =
322 case decl of
323 D.Definition (Valid.Definition pattern _ _) ->
324 ( Pattern.boundVars pattern
325 , []
326 )
328 D.Datatype name _ ctors ->
329 ( map (A.A region . fst) ctors
330 , [A.A region name]
331 )
333 D.TypeAlias name _ (A.A _ (Type.RRecord _ _)) ->
334 ( [A.A region name]
335 , [A.A region name]
336 )
338 D.TypeAlias name _ _ ->
339 ( []
340 , [A.A region name]
341 )
343 D.Port port ->
344 ( [A.A region (D.validPortName port)]
345 , []
346 )
348 D.Fixity _ _ _ ->
349 ( []
350 , []
351 )
354-- UNBOUND TYPE VARIABLES
356checkDecl :: Bool -> D.ValidDecl -> Result.Result wrn Error.Error ()
357checkDecl isRoot (A.A (region,_) decl) =
358 case decl of
359 D.Definition _ ->
360 return ()
362 D.Datatype name boundVars ctors ->
363 let frees = concatMap freeVars (concatMap snd ctors)
364 in
365 case findUnbound boundVars frees of
366 [] ->
367 return ()
369 unbound ->
370 let
371 (v:vs) = Set.toList (Set.fromList unbound)
372 in
373 Result.throw region
374 (Error.UnboundTypeVarsInUnion name boundVars v vs ctors)
376 D.TypeAlias name boundVars tipe ->
377 case findUnbound boundVars (freeVars tipe) of
378 [] ->
379 return ()
381 unbound ->
382 let
383 (v:vs) = Set.toList (Set.fromList unbound)
384 in
385 Result.throw region
386 (Error.UnboundTypeVarsInAlias name boundVars v vs tipe)
388 D.Port _ ->
389 if isRoot
390 then return ()
391 else Result.throw region Error.UnexpectedPort
393 D.Fixity _ _ _ ->
394 return ()
397findUnbound :: [String] -> [A.Located String] -> [String]
398findUnbound boundVars frees =
399 let bounds = Set.fromList boundVars
401 isUnbound x =
402 Set.notMember x bounds
403 in
404 filter isUnbound (map A.drop frees)
408freeVars :: Type.Raw -> [A.Located String]
409freeVars (A.A region tipe) =
410 case tipe of
411 Type.RLambda t1 t2 ->
412 freeVars t1 ++ freeVars t2
414 Type.RVar x ->
415 [A.A region x]
417 Type.RType _ ->
418 []
420 Type.RApp t ts ->
421 concatMap freeVars (t:ts)
423 Type.RRecord fields ext ->
424 maybe [] freeVars ext
425 ++ concatMap (freeVars . snd) fields