module Mueval.Context (cleanModules, defaultModules, unsafe) where

import Data.List (elem, isInfixOf)

{- | Return true if the String contains anywhere in it any keywords associated
   with dangerous functions. Unfortunately, this blacklist leaks like a sieve
   and will return many false positives (eg. 'unsafed "id \"unsafed\""' will
   evaluate to True, even though the phrase \"unsafe\" appears only in a String). But it
   will at least catch naive and simplistic invocations of "unsafePerformIO",
   "inlinePerformIO", and "unsafeCoerce". -}
unsafe :: String -> Bool
unsafe = \z -> any (`isInfixOf` z) ["unsafe", "inlinePerform", "liftIO", "Coerce", "Foreign",
                                    "Typeable", "Array", "IOBase", "Handle", "ByteString",
                                    "Editline", "GLUT", "lock", "ObjectIO", "System.Time",
                                    "OpenGL", "Control.Concurrent", "System.Posix",
                                    "throw", "Dyn", "cache", "stdin", "stdout", "stderr"]

-- | Return false if any of the listed modules cannot be found in the whitelist.
cleanModules :: [String] -> Bool
cleanModules = and . map (`elem` safeModules)

{- | Modules which we should load by default. These are of course whitelisted.
   Specifically, we want the Prelude because otherwise things are horribly
   crippled; we want SimpleReflect so we can do neat things (for said neat
   things, see
   and we want ShowQ and ShowFun to neuter IO stuff even more. -}
defaultModules :: [String]
defaultModules = ["Prelude", "ShowQ", "ShowFun", "SimpleReflect"]

-- | Borrowed from Lambdabot, this is the whitelist of modules which should be
--   safe to import functions from.
safeModules :: [String]
safeModules = defaultModules ++ ["Control.Applicative",