/curry-0.9.11/CaseCheck.lhs

# · Haskell · 244 lines · 205 code · 39 blank · 0 comment · 12 complexity · b3b7374e25b84e071be2fbdda96a70bf MD5 · raw file

  1. % -*- LaTeX -*-
  2. % $Id: CaseCheck.lhs 2101 2007-02-21 16:25:07Z wlux $
  3. %
  4. % Copyright (c) 2003-2007, Wolfgang Lux
  5. % See LICENSE for the full license.
  6. %
  7. \nwfilename{CaseCheck.lhs}
  8. \section{Case Mode Warnings}
  9. By default, Curry does not enforce capitalization conventions for
  10. identifiers. However, the compiler supports four different case modes
  11. and issues warnings when the selected case mode is not obeyed. The
  12. four supported modes are (cf.\ Sect.~C.1 of~\cite{Hanus:Report}):
  13. \begin{itemize}
  14. \item \emph{Free mode}: No constraints on the case of identifiers.
  15. \item \emph{Haskell mode}: Constructor names should start with an
  16. upper case letter, function and variable names with a lower case
  17. letter. In addition, data constructor symbol names should start with
  18. a colon and function symbol names should not start with a colon.
  19. \item \emph{Prolog mode}: Variable names should start with an upper
  20. case letter and function and constructor names with a lower case
  21. letter. No constraints for function and constructor symbols.
  22. \item \emph{G\"odel mode}: Variable names should start with a lower
  23. case letter and function and constructor names with an upper case
  24. letter. No constraints for function and constructor symbols.
  25. \end{itemize}
  26. In order to check identifier cases, the compiler collects and
  27. categorizes all type and value identifiers defined in the module. We
  28. recognize the following five identifier categories:
  29. \emph{TypeConstrId}, \emph{TypeVarId}, \emph{DataConstrId},
  30. \emph{FunctionId}, and \emph{VariableId}. At present, we do not check
  31. module names, even though Haskell requires them to start with an upper
  32. case letter.
  33. \begin{verbatim}
  34. > module CaseCheck(caseCheck,caseCheckGoal) where
  35. > import Base
  36. > import Char
  37. > import List
  38. > import Options
  39. > data Case =
  40. > UpperCase | LowerCase | ColonCase | NoColonCase
  41. > deriving (Eq,Show)
  42. > data Category =
  43. > TypeConstrId
  44. > | TypeVarId
  45. > | DataConstrId
  46. > | FunctionId
  47. > | VariableId
  48. > deriving Show
  49. > data Definition = D Position Category Ident
  50. > caseCheck :: CaseMode -> Module -> [String]
  51. > caseCheck cm m = check cm (definitions m)
  52. > caseCheckGoal :: CaseMode -> Goal -> [String]
  53. > caseCheckGoal cm g = check cm (goalDefinitions g)
  54. > check :: CaseMode -> [Definition] -> [String]
  55. > check FreeMode = const []
  56. > check HaskellMode = checkWith haskellMode
  57. > check PrologMode = checkWith prologMode
  58. > check GoedelMode = checkWith goedelMode
  59. > checkWith :: (Category -> [Case]) -> [Definition] -> [String]
  60. > checkWith f names =
  61. > [atP p (modeWarning x c cm) | D p c x <- names,
  62. > let cm = mode x,
  63. > cm `notElem` f c]
  64. \end{verbatim}
  65. Each case mode defines the admissible modes for all identifier
  66. categories.
  67. \begin{verbatim}
  68. > mode :: Ident -> Case
  69. > mode x
  70. > | isUpper c = UpperCase
  71. > | isLower c = LowerCase
  72. > | c == ':' = ColonCase
  73. > | otherwise = NoColonCase
  74. > where (c:_) = name x
  75. > haskellMode :: Category -> [Case]
  76. > haskellMode TypeConstrId = [UpperCase]
  77. > haskellMode TypeVarId = [LowerCase]
  78. > haskellMode DataConstrId = [UpperCase,ColonCase]
  79. > haskellMode FunctionId = [LowerCase,NoColonCase]
  80. > haskellMode VariableId = [LowerCase,NoColonCase]
  81. > prologMode :: Category -> [Case]
  82. > prologMode TypeConstrId = [LowerCase]
  83. > prologMode TypeVarId = [UpperCase]
  84. > prologMode DataConstrId = [LowerCase,ColonCase,NoColonCase]
  85. > prologMode FunctionId = [LowerCase,ColonCase,NoColonCase]
  86. > prologMode VariableId = [UpperCase]
  87. > goedelMode :: Category -> [Case]
  88. > goedelMode TypeConstrId = [UpperCase]
  89. > goedelMode TypeVarId = [LowerCase]
  90. > goedelMode DataConstrId = [UpperCase,ColonCase,NoColonCase]
  91. > goedelMode FunctionId = [UpperCase,ColonCase,NoColonCase]
  92. > goedelMode VariableId = [LowerCase]
  93. \end{verbatim}
  94. The usual traversal of the syntax tree is necessary in order to
  95. collect all defined identifiers.
  96. \begin{verbatim}
  97. > definitions :: Module -> [Definition]
  98. > definitions (Module _ _ _ ds) = names noPosition ds []
  99. > where noPosition = error "noPosition"
  100. > goalDefinitions :: Goal -> [Definition]
  101. > goalDefinitions (Goal p e ds) = names p ds (names p e [])
  102. > class SyntaxTree a where
  103. > names :: Position -> a -> [Definition] -> [Definition]
  104. > instance SyntaxTree a => SyntaxTree [a] where
  105. > names p xs ys = foldr (names p) ys xs
  106. > instance SyntaxTree TopDecl where
  107. > names _ (DataDecl p tc tvs cs) xs = typeNames p tc tvs ++ names p cs xs
  108. > names _ (NewtypeDecl p tc tvs nc) xs = typeNames p tc tvs ++ names p nc xs
  109. > names _ (TypeDecl p tc tvs _) xs = typeNames p tc tvs ++ xs
  110. > names p (BlockDecl d) xs = names p d xs
  111. > typeNames :: Position -> Ident -> [Ident] -> [Definition]
  112. > typeNames p tc tvs =
  113. > D p TypeConstrId tc : map (D p TypeVarId) (filter (not . isAnonId) tvs)
  114. > instance SyntaxTree ConstrDecl where
  115. > names _ (ConstrDecl p evs c _) xs = constrNames p evs c ++ xs
  116. > names _ (ConOpDecl p evs _ c _) xs = constrNames p evs c ++ xs
  117. > instance SyntaxTree NewConstrDecl where
  118. > names _ (NewConstrDecl p c _) xs = constrNames p [] c ++ xs
  119. > constrNames :: Position -> [Ident] -> Ident -> [Definition]
  120. > constrNames p evs c =
  121. > D p DataConstrId c : map (D p TypeVarId) (filter (not . isAnonId) evs)
  122. > instance SyntaxTree TypeExpr where
  123. > names p ty xs =
  124. > map (D p TypeVarId) (nub (filter (not . isAnonId) (fv ty))) ++ xs
  125. > instance SyntaxTree Decl where
  126. > names _ (InfixDecl _ _ _ _) xs = xs
  127. > names _ (TypeSig p _ ty) xs = names p ty xs
  128. > names _ (FunctionDecl p f eqs) xs = D p FunctionId f : names p eqs xs
  129. > names _ (ForeignDecl p _ _ _ f ty) xs = D p FunctionId f : names p ty xs
  130. > names _ (PatternDecl p t rhs) xs = names p t (names p rhs xs)
  131. > names _ (FreeDecl p vs) xs = map (D p VariableId) vs ++ xs
  132. > names _ (TrustAnnot _ _ _) xs = xs
  133. > instance SyntaxTree Equation where
  134. > names _ (Equation p lhs rhs) = names p lhs . names p rhs
  135. > instance SyntaxTree Lhs where
  136. > names p (FunLhs _ ts) = names p ts
  137. > names p (OpLhs t1 _ t2) = names p t1 . names p t2
  138. > names p (ApLhs lhs ts) = names p lhs . names p ts
  139. > instance SyntaxTree Rhs where
  140. > names _ (SimpleRhs p e ds) = names p ds . names p e
  141. > names p (GuardedRhs es ds) = names p ds . names p es
  142. > instance SyntaxTree ConstrTerm where
  143. > names _ (LiteralPattern _) xs = xs
  144. > names _ (NegativePattern _ _) xs = xs
  145. > names p (VariablePattern v) xs
  146. > | isAnonId v = xs
  147. > | otherwise = D p VariableId v : xs
  148. > names p (ConstructorPattern _ ts) xs = names p ts xs
  149. > names p (InfixPattern t1 _ t2) xs = names p t1 (names p t2 xs)
  150. > names p (ParenPattern t) xs = names p t xs
  151. > names p (TuplePattern ts) xs = names p ts xs
  152. > names p (ListPattern ts) xs = names p ts xs
  153. > names p (AsPattern v t) xs = D p VariableId v : names p t xs
  154. > names p (LazyPattern t) xs = names p t xs
  155. > instance SyntaxTree CondExpr where
  156. > names _ (CondExpr p g e) = names p g . names p e
  157. > instance SyntaxTree Expression where
  158. > names _ (Literal _) = id
  159. > names _ (Variable _) = id
  160. > names _ (Constructor _) = id
  161. > names p (Paren e) = names p e
  162. > names p (Typed e ty) = names p e . names p ty
  163. > names p (Tuple es) = names p es
  164. > names p (List es) = names p es
  165. > names p (ListCompr e sts) = names p sts . names p e
  166. > names p (EnumFrom e) = names p e
  167. > names p (EnumFromThen e1 e2) = names p e1 . names p e2
  168. > names p (EnumFromTo e1 e2) = names p e1 . names p e2
  169. > names p (EnumFromThenTo e1 e2 e3) = names p e1 . names p e2 . names p e3
  170. > names p (UnaryMinus _ e) = names p e
  171. > names p (Apply e1 e2) = names p e1 . names p e2
  172. > names p (InfixApply e1 _ e2) = names p e1 . names p e2
  173. > names p (LeftSection e _) = names p e
  174. > names p (RightSection _ e) = names p e
  175. > names p (Lambda ts e) = names p ts . names p e
  176. > names p (Let ds e) = names p ds . names p e
  177. > names p (Do sts e) = names p sts . names p e
  178. > names p (IfThenElse e1 e2 e3) = names p e1 . names p e2 . names p e3
  179. > names p (Case e as) = names p e . names p as
  180. > instance SyntaxTree Statement where
  181. > names p (StmtExpr e) = names p e
  182. > names p (StmtDecl ds) = names p ds
  183. > names p (StmtBind t e) = names p t . names p e
  184. > instance SyntaxTree Alt where
  185. > names _ (Alt p t rhs) = names p t . names p rhs
  186. > isAnonId :: Ident -> Bool
  187. > isAnonId x = unRenameIdent x == anonId
  188. \end{verbatim}
  189. Warning messages.
  190. \begin{verbatim}
  191. > modeWarning :: Ident -> Category -> Case -> String
  192. > modeWarning x c cm =
  193. > "Warning: name of " ++ kind c ++ " " ++ name x ++ " " ++ start cm
  194. > kind :: Category -> String
  195. > kind TypeConstrId = "type constructor"
  196. > kind TypeVarId = "type variable"
  197. > kind DataConstrId = "data constructor"
  198. > kind FunctionId = "function"
  199. > kind VariableId = "variable"
  200. > start :: Case -> String
  201. > start UpperCase = "starts with an upper case letter"
  202. > start LowerCase = "starts with a lower case letter"
  203. > start ColonCase = "starts with a colon"
  204. > start NoColonCase = "does not start with a colon"
  205. \end{verbatim}