husk-scheme 3.4.4 → 3.5.1
raw patch · 13 files changed
+103/−69 lines, 13 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Language.Scheme.Core: eval :: Env -> LispVal -> LispVal -> IOThrowsError LispVal
+ Language.Scheme.Core: apply :: LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal
+ Language.Scheme.Core: continueEval :: Env -> LispVal -> LispVal -> IOThrowsError LispVal
+ Language.Scheme.Types: HFunc :: [String] -> (Maybe String) -> (Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal) -> Env -> LispVal
+ Language.Scheme.Types: hbody :: LispVal -> (Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal)
+ Language.Scheme.Types: hclosure :: LispVal -> Env
+ Language.Scheme.Types: hparams :: LispVal -> [String]
+ Language.Scheme.Types: hvararg :: LispVal -> (Maybe String)
- Language.Scheme.Types: Environment :: (Maybe Env) -> (IORef [((String, String), IORef LispVal)]) -> Env
+ Language.Scheme.Types: Environment :: (Maybe Env) -> (IORef (Map (String, String) (IORef LispVal))) -> Env
- Language.Scheme.Types: bindings :: Env -> (IORef [((String, String), IORef LispVal)])
+ Language.Scheme.Types: bindings :: Env -> (IORef (Map (String, String) (IORef LispVal)))
Files
- README.markdown +1/−1
- hs-src/Language/Scheme/Core.hs +29/−10
- hs-src/Language/Scheme/FFI.hs +0/−4
- hs-src/Language/Scheme/Macro.hs +1/−4
- hs-src/Language/Scheme/Macro/Matches.hs +0/−4
- hs-src/Language/Scheme/Numerical.hs +0/−4
- hs-src/Language/Scheme/Parser.hs +0/−4
- hs-src/Language/Scheme/Plugins/CPUTime.hs +0/−4
- hs-src/Language/Scheme/Primitives.hs +0/−4
- hs-src/Language/Scheme/Types.hs +42/−9
- hs-src/Language/Scheme/Variables.hs +19/−11
- hs-src/shell.hs +3/−6
- husk-scheme.cabal +8/−4
README.markdown view
@@ -94,7 +94,7 @@ - [cabal-install](http://hackage.haskell.org/trac/hackage/wiki/CabalInstall) may be used to build, deploy, and generate packages for husk. - [Haskeline](http://trac.haskell.org/haskeline) - which may be installed using cabal: `cabal install haskeline` -The `scm-unit-tests` directory contains unit tests for much of the scheme code. All tests may be executed via the `make test` command.+The `tests` directory contains unit tests for much of the scheme code. All tests may be executed via the `make test` command. The `examples` directory contains example scheme programs.
hs-src/Language/Scheme/Core.hs view
@@ -7,19 +7,17 @@ Stability : experimental Portability : portable -husk scheme interpreter--A lightweight dialect of R5RS scheme.- This module contains Core functionality, primarily Scheme expression evaluation. -} module Language.Scheme.Core- ( eval- , evalLisp+ (+ evalLisp , evalString , evalAndPrint , primitiveBindings+ , apply+ , continueEval ) where import qualified Language.Scheme.FFI import qualified Language.Scheme.Macro@@ -57,8 +55,7 @@ evalAndPrint :: Env -> String -> IO () evalAndPrint env expr = evalString env expr >>= putStrLn -{- |Evaluate lisp code that has already been loaded into haskell-FUTURE: code example for this, via ghci and/or a custom Haskell program. -}+-- |Evaluate lisp code that has already been loaded into haskell evalLisp :: Env -> LispVal -> IOThrowsError LispVal evalLisp env lisp = meval env (makeNullContinuation env) lisp @@ -96,7 +93,7 @@ return val -} -{- continueEval is a support function for eval, below.+{- |continueEval is a support function for eval. - - Transformed eval section into CPS by calling into this instead of returning from eval. - This function uses the cont argument to determine whether to keep going or to finally@@ -645,7 +642,7 @@ -> m LispVal makeVarargs = makeFunc . Just . showVal --- Call into a Scheme function+-- |Call into a Scheme function apply :: LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal apply _ cont@(Continuation env ccont ncont _ ndynwind) args = do -- case (trace ("calling into continuation. dynWind = " ++ show ndynwind) ndynwind) of@@ -705,6 +702,28 @@ -- Shortcut for calling continueEval continueWCont cwcEnv cwcBody cwcCont cwcDynWind = continueEval cwcEnv (Continuation cwcEnv (Just (SchemeBody cwcBody)) (Just cwcCont) Nothing cwcDynWind) $ Nil ""++ bindVarArgs arg env = case arg of+ Just argName -> liftIO $ extendEnv env [((varNamespace, argName), List $ remainingArgs)]+ Nothing -> return env+apply cont (HFunc aparams avarargs abody aclosure) args =+ if num aparams /= num args && avarargs == Nothing+ then throwError $ NumArgs (num aparams) args+ else (liftIO $ extendEnv aclosure $ zip (map ((,) varNamespace) aparams) args) >>= bindVarArgs avarargs >>= (evalBody abody)+ where remainingArgs = drop (length aparams) args+ num = toInteger . length+ evalBody evBody env = evBody env cont (Nil "") Nothing +{- TODO: may need to handle cases from Func, such as dynamic winders+ case cont of+ Continuation _ (Just (SchemeBody cBody)) (Just cCont) _ cDynWind -> if length cBody == 0+ then continueWCont env (evBody) cCont cDynWind+ else continueWCont env (evBody) cont cDynWind -- Might be a problem, not fully optimizing+ Continuation _ _ _ _ cDynWind -> continueWCont env (evBody) cont cDynWind+ _ -> continueWCont env (evBody) cont Nothing++ -- Shortcut for calling continueEval+ continueWCont cwcEnv cwcBody cwcCont cwcDynWind =+ continueEval cwcEnv (Continuation cwcEnv (Just (SchemeBody cwcBody)) (Just cwcCont) Nothing cwcDynWind) $ Nil ""-} bindVarArgs arg env = case arg of Just argName -> liftIO $ extendEnv env [((varNamespace, argName), List $ remainingArgs)]
hs-src/Language/Scheme/FFI.hs view
@@ -9,10 +9,6 @@ Stability : experimental Portability : non-portable (GHC API) -husk scheme interpreter--A lightweight dialect of R5RS scheme.- This module contains the foreign function interface. -} module Language.Scheme.FFI (evalfuncLoadFFI) where
hs-src/Language/Scheme/Macro.hs view
@@ -7,10 +7,6 @@ Stability : experimental Portability : portable -husk scheme interpreter--A lightweight dialect of R5RS scheme.- This module contains code for hygienic macros. Hygienic macros are implemented using the algorithm from the paper@@ -25,6 +21,7 @@ At a high level, macro transformation is broken down into the following steps: + 0) Walk the input code looking for a macro definition or macro call. If a macro call is found - 1) Search for a rule that matches the input. During this process, any pattern variables in the input are loaded into a temporary environment 2) If a rule matches,
hs-src/Language/Scheme/Macro/Matches.hs view
@@ -7,10 +7,6 @@ Stability : experimental Portability : portable -husk scheme interpreter--A lightweight dialect of R5RS scheme.- This module contains utility functions used to support macro processing, by storing and/or manipulating data involving 0-or-many matches. -}
hs-src/Language/Scheme/Numerical.hs view
@@ -7,10 +7,6 @@ Stability : experimental Portability : portable -husk scheme interpreter--A lightweight dialect of R5RS scheme.- This module implements the numerical tower. -}
hs-src/Language/Scheme/Parser.hs view
@@ -8,10 +8,6 @@ Stability : experimental Portability : portable -husk scheme interpreter--A lightweight dialect of R5RS scheme.- This module implements parsing of Scheme code. -}
hs-src/Language/Scheme/Plugins/CPUTime.hs view
@@ -7,10 +7,6 @@ Stability : experimental Portability : portable -husk scheme interpreter--A lightweight dialect of R5RS scheme.- This module wraps System.CPUTime so that it can be used directly by Scheme code. More importantly, it serves as an example of how to wrap existing Haskell code so
hs-src/Language/Scheme/Primitives.hs view
@@ -7,10 +7,6 @@ Stability : experimental Portability : portable -husk scheme interpreter--A lightweight dialect of R5RS scheme.- This module contains Primitive functions written in Haskell. -}
hs-src/Language/Scheme/Types.hs view
@@ -7,13 +7,7 @@ Stability : experimental Portability : portable -husk scheme interpreter--A lightweight dialect of R5RS scheme.--This module contains top-level data type definitions and their associated functions, including:- - Scheme data types- - Scheme errors+This module contains top-level data type definitions, environments, error types, and associated functions. -} @@ -30,11 +24,14 @@ -- Environment management -- |A Scheme environment containing variable bindings of form @(namespaceName, variableName), variableValue@-data Env = Environment {parentEnv :: (Maybe Env), bindings :: (IORef [((String, String), IORef LispVal)])} -- lookup via: (namespace, variable)+data Env = Environment {+ parentEnv :: (Maybe Env), + bindings :: (IORef (Data.Map.Map (String, String) (IORef LispVal)))+ } -- |An empty environment nullEnv :: IO Env-nullEnv = do nullBindings <- newIORef []+nullEnv = do nullBindings <- newIORef $ Data.Map.fromList [] return $ Environment Nothing nullBindings -- Internal namespace for macros@@ -137,6 +134,12 @@ closure :: Env } -- ^Function+ | HFunc {hparams :: [String],+ hvararg :: (Maybe String),+ hbody :: (Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal),+ hclosure :: Env+ }+ -- ^Function formed from a Haskell function | IOFunc ([LispVal] -> IOThrowsError LispVal) -- ^Primitive function within the IO monad | EvalFunc ([LispVal] -> IOThrowsError LispVal)@@ -232,10 +235,34 @@ eqv [(HashTable arg1), (HashTable arg2)] = eqv [List $ (map (\ (x, y) -> List [x, y]) $ Data.Map.toAscList arg1), List $ (map (\ (x, y) -> List [x, y]) $ Data.Map.toAscList arg2)]+--+-- This comparison function may be too simplistic. Basically we check to see if+-- functions have the same calling interface. If they do, then we compare the +-- function bodies for equality.+--+--FUTURE:+--+-- The real solution for this and many of the other comparison functions is to+-- assign memory locations to data. Then we can just compare memory locations+-- in cases such as this one. But that is a much larger change.+eqv [x@(Func _ _ xBody _), y@(Func _ _ yBody _)] = do+ if (show x) /= (show y)+ then return $ Bool False+ else eqvList eqv [List xBody, List yBody] +eqv [x@(HFunc _ _ xBody _), y@(Func _ _ yBody _)] = do+ if (show x) /= (show y)+ then return $ Bool False+ else return $ Bool True -- TODO: compare high-order functions... eqvList eqv [List xBody, List yBody] +--+eqv [x@(PrimitiveFunc _), y@(PrimitiveFunc _)] = return $ Bool $ (show x) == (show y)+eqv [x@(IOFunc _), y@(IOFunc _)] = return $ Bool $ (show x) == (show y)+eqv [x@(EvalFunc _), y@(EvalFunc _)] = return $ Bool $ (show x) == (show y)+-- FUTURE: comparison of two continuations eqv [l1@(List _), l2@(List _)] = eqvList eqv [l1, l2] eqv [_, _] = return $ Bool False eqv badArgList = throwError $ NumArgs 2 badArgList +-- |Compare two lists of haskell values, using the given comparison function eqvList :: ([LispVal] -> ThrowsError LispVal) -> [LispVal] -> ThrowsError LispVal eqvList eqvFunc [(List arg1), (List arg2)] = return $ Bool $ (length arg1 == length arg2) && (all eqvPair $ zip arg1 arg2)@@ -281,10 +308,16 @@ (case varargs of Nothing -> "" Just arg -> " . " ++ arg) ++ ") ...)"+showVal (HFunc {hparams = args, hvararg = varargs, hbody = _, hclosure = _}) =+ "(lambda (" ++ unwords (map show args) +++ (case varargs of+ Nothing -> ""+ Just arg -> " . " ++ arg) ++ ") ...)" showVal (Port _) = "<IO port>" showVal (IOFunc _) = "<IO primitive>" showVal (EvalFunc _) = "<procedure>" +-- |Convert a list of Lisp objects into a space-separated string unwordsList :: [LispVal] -> String unwordsList = unwords . map showVal
hs-src/Language/Scheme/Variables.hs view
@@ -7,10 +7,6 @@ Stability : experimental Portability : portable -husk scheme interpreter--A lightweight dialect of R5RS scheme.- This module contains code for working with Scheme variables. -}@@ -19,7 +15,13 @@ import Language.Scheme.Types import Control.Monad.Error import Data.IORef+import qualified Data.Map ++-- TODO: convert from storing vars in a list to a more efficient+-- data structure using Data.Map++ {- Experimental code: -- From: http://rafaelbarreto.com/2011/08/21/comparing-objects-by-memory-location-in-haskell/ import Foreign@@ -52,7 +54,7 @@ printEnv :: Env -> IO String printEnv env = do binds <- liftIO $ readIORef $ bindings env- l <- mapM showVar binds + l <- mapM showVar $ Data.Map.toList binds return $ unlines l where showVar ((_, name), val) = do@@ -63,7 +65,9 @@ copyEnv :: Env -> IO Env copyEnv env = do binds <- liftIO $ readIORef $ bindings env- bindingList <- mapM addBinding binds >>= newIORef+-- bindingList <- mapM addBinding binds >>= newIORef+ bindingListT <- mapM addBinding $ Data.Map.toList binds -- TODO: there is a more elegant way to write this here (and below, too)+ bindingList <- newIORef $ Data.Map.fromList bindingListT return $ Environment (parentEnv env) bindingList -- TODO: recursively create a copy of parent also? where addBinding ((namespace, name), val) = do --ref <- newIORef $ liftIO $ readIORef val x <- liftIO $ readIORef val@@ -71,8 +75,11 @@ return ((namespace, name), ref) -- |Extend given environment by binding a series of values to a new environment.++-- TODO: should be able to use Data.Map.fromList to ease construction of new Env extendEnv :: Env -> [((String, String), LispVal)] -> IO Env-extendEnv envRef abindings = do bindinglist <- mapM addBinding abindings >>= newIORef+extendEnv envRef abindings = do bindinglistT <- (mapM addBinding abindings) -- >>= newIORef+ bindinglist <- newIORef $ Data.Map.fromList bindinglistT return $ Environment (Just envRef) bindinglist where addBinding ((namespace, name), val) = do ref <- newIORef val return ((namespace, name), ref)@@ -97,7 +104,8 @@ -- |Determine if a variable is bound in a given namespace isNamespacedBound :: Env -> String -> String -> IO Bool-isNamespacedBound envRef namespace var = (readIORef $ bindings envRef) >>= return . maybe False (const True) . lookup (namespace, var)+isNamespacedBound envRef namespace var = + (readIORef $ bindings envRef) >>= return . Data.Map.member (namespace, var) -- TODO: should isNamespacedBound be replaced with this? Probably, but one step at a time... isNamespacedRecBound :: Env -> String -> String -> IO Bool@@ -116,7 +124,7 @@ getNamespacedVar envRef namespace var = do binds <- liftIO $ readIORef $ bindings envRef- case lookup (namespace, var) binds of+ case Data.Map.lookup (namespace, var) binds of (Just a) -> liftIO $ readIORef a Nothing -> case parentEnv envRef of (Just par) -> getNamespacedVar par namespace var@@ -135,7 +143,7 @@ setNamespacedVar envRef namespace var value = do env <- liftIO $ readIORef $ bindings envRef- case lookup (namespace, var) env of+ case Data.Map.lookup (namespace, var) env of (Just a) -> do -- vprime <- liftIO $ readIORef a liftIO $ writeIORef a value return value@@ -154,5 +162,5 @@ else liftIO $ do valueRef <- newIORef value env <- readIORef $ bindings envRef- writeIORef (bindings envRef) (((namespace, var), valueRef) : env)+ writeIORef (bindings envRef) (Data.Map.insert (namespace, var) valueRef env) -- (((namespace, var), valueRef) : env) return value
hs-src/shell.hs view
@@ -7,10 +7,6 @@ Stability : experimental Portability : portable -husk scheme interpreter--A lightweight dialect of R5RS scheme.- This file implements a REPL "shell" to host the interpreter, and also allows execution of stand-alone files containing Scheme code. -}@@ -67,8 +63,9 @@ putStrLn " | | | | |_| \\__ \\ < /// \\\\\\ \\__ \\ (__| | | | __/ | | | | | __/ " putStrLn " |_| |_|\\__,_|___/_|\\_\\ /// \\\\\\ |___/\\___|_| |_|\\___|_| |_| |_|\\___| " putStrLn " "- putStrLn " http://justinethier.github.com/husk-scheme Version 3.4.4 "- putStrLn " (c) 2010-2011 Justin Ethier "+ putStrLn " http://justinethier.github.com/husk-scheme "+ putStrLn " (c) 2010-2012 Justin Ethier "+ putStrLn " Version 3.5.1 " putStrLn " " runRepl :: IO ()
husk-scheme.cabal view
@@ -1,5 +1,5 @@ Name: husk-scheme-Version: 3.4.4+Version: 3.5.1 Synopsis: R5RS Scheme interpreter program and library. Description: A dialect of R5RS Scheme written in Haskell. Provides advanced features including continuations, hygienic macros, a Haskell FFI,@@ -8,15 +8,19 @@ License-file: LICENSE Author: Justin Ethier Maintainer: Justin Ethier <github.com/justinethier>-Homepage: https://github.com/justinethier/husk-scheme-Cabal-Version: >= 1.4+Homepage: http://justinethier.github.com/husk-scheme+Cabal-Version: >= 1.6 Build-Type: Simple Category: Compilers/Interpreters, Language-Tested-with: GHC == 7.0.2, GHC == 6.12.3, GHC == 6.10.4+Tested-with: GHC == 7.2.2, GHC == 7.0.2, GHC == 6.12.3, GHC == 6.10.4 Extra-Source-Files: README.markdown LICENSE Data-Files: stdlib.scm++Source-Repository head+ Type: git+ Location: git://github.com/justinethier/husk-scheme.git Library Build-Depends: base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory, ghc, ghc-paths