mueval 0.6.1 → 0.6.2
raw patch · 6 files changed
+74/−38 lines, 6 files
Files
- Mueval/Concurrent.hs +3/−2
- Mueval/Context.hs +33/−25
- Mueval/Interpreter.hs +8/−5
- Mueval/ParseArgs.hs +6/−1
- mueval.cabal +3/−3
- tests.sh +21/−2
Mueval/Concurrent.hs view
@@ -14,7 +14,7 @@ watchDog tout tid = do installHandler sigXCPU (CatchOnce $ throwTo tid $ ErrorCall "Time limit exceeded.") Nothing- forkIO $ do threadDelay (tout * 1000000)+ forkIO $ do threadDelay (tout * 500000) -- Time's up. It's a good day to die. throwTo tid (ErrorCall "Time limit exceeded") yield -- give the other thread a chance@@ -42,9 +42,10 @@ forkIO (interpreterSession typeprint extend mdls fls expr `catchDyn` (printInterpreterError) >> putMVar mvar "Done.")- where mdls = modules opts+ where mdls = if impq then Nothing else Just (modules opts) expr = expression opts tout = timeLimit opts typeprint = printType opts extend = extensions opts fls = loadFile opts+ impq = noimports opts
Mueval/Context.hs view
@@ -24,18 +24,11 @@ crippled; we want SimpleReflect so we can do neat things (for said neat things, see <http://twan.home.fmf.nl/blog/haskell/simple-reflection-of-expressions.details>);- and we want ShowQ and ShowFun to neuter IO stuff even more. -}+ and we want ShowQ and ShowFun to neuter IO stuff even more.+ The rest should be safe to import without clashes, according to the Lambdabot+ sources. -} 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",- "Control.Arrow",- "Control.Arrow.Operations",- "Control.Arrow.Transformer",- "Control.Arrow.Transformer.All",+defaultModules = ["Prelude", "ShowQ", "ShowFun", "SimpleReflect", "Data.Function", "Control.Monad", "Control.Monad.Cont", "Control.Monad.Error",@@ -53,27 +46,16 @@ "Data.Array", "Data.Bits", "Data.Bool",- "Data.ByteString",- "Data.ByteString.Char8",- "Data.ByteString.Lazy",- "Data.ByteString.Lazy.Char8", "Data.Char", "Data.Complex", "Data.Dynamic", "Data.Either", "Data.Eq", "Data.Fixed",- "Data.Foldable",- "Data.Function",- "Data.Generics",- "Data.Generics", "Data.Graph", "Data.Int",- "Data.IntMap",- "Data.IntSet", "Data.Ix", "Data.List",- "Data.Map", "Data.Maybe", "Data.Monoid", "Data.Number.BigFloat",@@ -85,9 +67,6 @@ "Data.Number.Symbolic", "Data.Ord", "Data.Ratio",- "Data.Sequence",- "Data.Set",- "Data.Traversable", "Data.Tree", "Data.Tuple", "Data.Typeable",@@ -97,3 +76,32 @@ "Test.QuickCheck", "Text.PrettyPrint.HughesPJ", "Text.Printf"]++{- | Borrowed from Lambdabot, this is the whitelist of modules which should be+ safe to import functions from, but which we don't want to import by+ default.+ FIXME: make these qualified imports. The GHC API & Hint currently do not+ support qualified imports.+ WARNING: You can import these with --module, certainly, but the onus is on+ the user to make sure they fully disambiguate function names; ie:++ > mueval --module Data.Map -e "Prelude.map (+1) [1..100]"+-}+safeModules :: [String]+safeModules = defaultModules ++ ["Control.Applicative",+ "Control.Arrow",+ "Control.Arrow.Operations",+ "Control.Arrow.Transformer",+ "Control.Arrow.Transformer.All",+ "Data.ByteString",+ "Data.ByteString.Char8",+ "Data.ByteString.Lazy",+ "Data.ByteString.Lazy.Char8",+ "Data.Foldable",+ "Data.Generics",+ "Data.IntMap",+ "Data.IntSet",+ "Data.Map",+ "Data.Sequence",+ "Data.Set",+ "Data.Traversable"]
Mueval/Interpreter.hs view
@@ -34,7 +34,7 @@ optimizations, hide all packages, make sure one cannot call unimported functions, typecheck (and optionally print it), set resource limits for this thread, and do some error handling. -}-interpreter :: Bool -> Bool -> [ModuleName] -> String -> String -> Interpreter ()+interpreter :: Bool -> Bool -> Maybe [ModuleName] -> String -> String -> Interpreter () interpreter prt exts modules lfl expr = do setUseLanguageExtensions exts -- False by default @@ -45,7 +45,8 @@ reset -- Make sure nothing is available setInstalledModsAreInScopeQualified False - let doload = if lfl == "" then False else True+ let doload = if lfl == ""+ then False else True when doload (liftIO $ mvload lfl) @@ -59,7 +60,9 @@ -- module setTopLevelModules [(takeWhile (/='.') lfl')] - setImports modules+ case modules of+ Nothing -> return ()+ Just ms -> setImports ms when prt (say $ expr ++ "\n") @@ -70,14 +73,14 @@ say "\n" else return () result <- eval expr- say $ show result ++ "\n"+ say $ result ++ "\n" else error "Expression did not type check." -- | Wrapper around 'interpreter'; supplies a fresh GHC API session and -- error-handling. The arguments are simply passed on. interpreterSession :: Bool -- ^ Whether to print inferred type -> Bool -- ^ Whether to use GHC extensions- -> [ModuleName] -- ^ A list of modules we wish to be visible+ -> Maybe [ModuleName] -- ^ A list of modules we wish to be visible -> String -- ^ A local file from which to grab definitions; an -- empty string is treated as no file. -> String -- ^ The string to be interpreted as a Haskell expression
Mueval/ParseArgs.hs view
@@ -17,6 +17,7 @@ , user :: String , printType :: Bool , extensions :: Bool+ , noimports :: Bool } deriving Show defaultOptions :: Options@@ -26,7 +27,8 @@ , user = "" , loadFile = "" , printType = False- , extensions = False }+ , extensions = False+ , noimports = False } options :: [OptDescr (Options -> Options)] options = [Option ['p'] ["password"]@@ -43,6 +45,9 @@ Option ['m'] ["module"] (ReqArg (\m opts -> opts { modules = m:(modules opts) }) "MODULE") "A module we should import functions from for evaluation. (Can be given multiple times.)",+ Option ['n'] ["noimports"]+ (NoArg (\opts -> opts { noimports = True}))+ "Whether to import any default modules, such as Prelude; this is useful if you are loading a file which, say, redefines Prelude operators.", Option ['E'] ["Extensions"] (NoArg (\opts -> opts { extensions = True})) "Whether to enable the Glasgow extensions to Haskell '98. Defaults to false, but enabling is useful for QuickCheck.",
mueval.cabal view
@@ -1,5 +1,5 @@ name: mueval-version: 0.6.1+version: 0.6.2 license: BSD3 license-file: LICENSE@@ -32,9 +32,9 @@ exposed-modules: Mueval.Concurrent, Mueval.Context, Mueval.Interpreter, Mueval.ParseArgs, Mueval.Resources build-depends: base, directory, mtl, filepath, unix, hint>=0.2.4, show>=0.3, utf8-string- ghc-options: -Wall -static+ ghc-options: -Wall -static -O2 executable mueval main-is: main.hs build-depends: base- ghc-options: -Wall -threaded -static+ ghc-options: -Wall -static -O2
tests.sh view
@@ -9,7 +9,7 @@ # Test on valid expressions. Note we conditionalize - all of these should return successfully. echo "Test some valid expressions \n" ## Does anything work?-m 'False'+m 'True' ## OK, let's try some simple math. m '1*100+1' m '(1*100) +1+1' --module Control.Monad@@ -37,6 +37,20 @@ m 'mysmallcheck (\x -> not x || x)' -E ## Test Unicode. If this fails, characters got mangled somewhere. m 'let (ñ) = (+) in ñ 5 5'+## Test default imports & have some function fun+m 'fix (1:)'+m 'fix show'+m 'let fix f = let x = f x in x in fix show'+m '(+1) . (*2) $ 10'+m 'fmap fix return 42'+m 'filterM (const [False,True]) [1,2,3]'+m 'sequence [[1,2,3],[4,5]]'+m 'sort [4,6,1,2,3]'+m 'runIdentity $ mfix (return . (0:) . scanl (+) 1)'+m 'fix ((1:).(1:).(zipWith (+) `ap` tail))'+m 'runST (return 0)'+## Test defaulting of expressions+m 'show []' -E ## Now let's do file loading echo "module TmpModule (foo, bar) where\nfoo x = x + 1 \nbar x = x + 2" > "TmpModule.hs" m '1+1' --loadfile="TmpModule.hs"@@ -44,6 +58,9 @@ m 'bar 1' --loadfile="TmpModule.hs" m 'foo $ foo 1' --loadfile="TmpModule.hs" rm "TmpModule.hs"+## Test the --noimports function+## TODO: more extensive tests of this+m '()' --noimports echo "\nOK, all the valid expressions worked out well." && # Test on bad or outright evil expressions@@ -54,14 +71,16 @@ m 'let x = x + 1 in x' || ## Similarly, but with a strict twist m 'let f :: Int -> Int; f x = f $! (x+1) in f 0' ||-## test stack limits+## test stack overflow limits m 'let x = 1 + x in x' ||+m 'let fix f = let x = f x in x in foldr (.) id (repeat read) $ fix show' || ## Let's stress the time limits m 'let {p x y f = f x y; f x = p x x} in f (f (f (f (f (f (f (f (f (f (f (f (f (f (f (f (f (f (f f)))))))))))))))))) f' || ## Now let's test the module whitelisting m 1+1 --module Data.List --module System.IO.Unsafe --module Control.Monad || m "let foo = unsafePerformIO readFile \"/etc/passwd\" in foo" --module System.IO.Unsafe || m "head [1..]" --module Data.List --module Text.HTML.Download ||+m " runST (unsafeIOToST (readFile \"/etc/passwd\"))" || ### Can we bypass the whitelisting by fully qualified module names? m "Foreign.unsafePerformIO $ readFile \"/etc/passwd\"" || m "Data.ByteString.Internal.inlinePerformIO $ readFile \"/etc/passwd\"" ||