forked from purescript/purescript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLinter.hs
More file actions
73 lines (61 loc) · 2.57 KB
/
Linter.hs
File metadata and controls
73 lines (61 loc) · 2.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
-----------------------------------------------------------------------------
--
-- Module : Language.PureScript.Linter
-- Copyright : (c) Copyright 2015 PureScript
-- License : MIT
--
-- Maintainer : Phil Freeman <paf31@cantab.net>
-- Stability : experimental
-- Portability :
--
-- | This module implements a simple linting pass on the PureScript AST.
--
-----------------------------------------------------------------------------
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Language.PureScript.Linter (lint) where
import Data.List (mapAccumL, nub)
import Data.Maybe (mapMaybe)
import Data.Monoid
import qualified Data.Set as S
import Control.Applicative
import Control.Monad.Writer.Class
import Language.PureScript.AST
import Language.PureScript.Names
import Language.PureScript.Errors
-- | Lint the PureScript AST.
-- |
-- | Right now, this pass only performs a shadowing check.
lint :: forall m. (Applicative m, MonadWriter MultipleErrors m) => Module -> m ()
lint (Module _ mn ds _) = censor (onErrorMessages (ErrorInModule mn)) $ mapM_ lintDeclaration ds
where
moduleNames :: S.Set Ident
moduleNames = S.fromList (nub (mapMaybe getDeclIdent ds))
getDeclIdent :: Declaration -> Maybe Ident
getDeclIdent (PositionedDeclaration _ _ d) = getDeclIdent d
getDeclIdent (ValueDeclaration ident _ _ _) = Just ident
getDeclIdent (ExternDeclaration ident _) = Just ident
getDeclIdent (ExternInstanceDeclaration ident _ _ _) = Just ident
getDeclIdent (TypeInstanceDeclaration ident _ _ _ _) = Just ident
getDeclIdent (BindingGroupDeclaration _) = error "lint: binding groups should not be desugared yet."
getDeclIdent _ = Nothing
lintDeclaration :: Declaration -> m ()
lintDeclaration d =
let (f, _, _, _, _) = everythingWithContextOnValues moduleNames mempty mappend def stepE stepB def def
in tell (f d)
where
def s _ = (s, mempty)
stepE :: S.Set Ident -> Expr -> (S.Set Ident, MultipleErrors)
stepE s (Abs (Left name) _) = bind s name
stepE s (Let ds' _) =
case mapAccumL bind s (nub (mapMaybe getDeclIdent ds')) of
(s', es) -> (s', mconcat es)
stepE s _ = (s, mempty)
stepB :: S.Set Ident -> Binder -> (S.Set Ident, MultipleErrors)
stepB s (VarBinder name) = bind s name
stepB s (NamedBinder name _) = bind s name
stepB s _ = (s, mempty)
bind :: S.Set Ident -> Ident -> (S.Set Ident, MultipleErrors)
bind s name | name `S.member` s = (s, errorMessage (ShadowedName name))
| otherwise = (S.insert name s, mempty)