packages feed

husk-scheme 3.5.3.2 → 3.5.4

raw patch · 13 files changed

+411/−104 lines, 13 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Language.Scheme.Numerical: foldl1M :: Monad m => (a -> a -> m a) -> [a] -> m a
- Language.Scheme.Numerical: foldlM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
- Language.Scheme.Parser: dot :: ParsecT String () Identity String
- Language.Scheme.Parser: identifier :: ParsecT String () Identity String
- Language.Scheme.Parser: lexeme :: ParsecT String () Identity a -> ParsecT String () Identity a
- Language.Scheme.Parser: lexer :: GenTokenParser String () Identity
- Language.Scheme.Parser: parens :: ParsecT String () Identity a -> ParsecT String () Identity a
- Language.Scheme.Parser: whiteSpace :: ParsecT String () Identity ()
- Language.Scheme.Primitives: AnyUnpacker :: (LispVal -> ThrowsError a) -> Unpacker
- Language.Scheme.Primitives: data Unpacker
- Language.Scheme.Variables: setVar, defineVar :: Env -> String -> LispVal -> IOThrowsError LispVal
+ Language.Scheme.Types: runIOThrowsREPL :: IOThrowsError String -> IO String
+ Language.Scheme.Variables: defineVar :: Env -> String -> LispVal -> IOThrowsError LispVal
+ Language.Scheme.Variables: setVar :: Env -> String -> LispVal -> IOThrowsError LispVal
- Language.Scheme.Types: runIOThrows :: IOThrowsError String -> IO String
+ Language.Scheme.Types: runIOThrows :: IOThrowsError String -> IO (Maybe String)

Files

hs-src/Compiler/huskc.hs view
@@ -30,7 +30,7 @@   putStrLn ""   putStrLn "!!! This version of huskc is Experimental !!!"   putStrLn ""-  putStrLn "It is recommended you consult the issue list prior to use:"+  putStrLn "You might want to consult the issue list before use:"   putStrLn "https://github.com/justinethier/husk-scheme/issues"   putStrLn "" @@ -134,8 +134,8 @@   stdlib <- getDataFileName "stdlib.scm"   result <- (runIOThrows $ liftM show $ compileSchemeFile env (stdlib) inFile)   case result of-   "" -> compileHaskellFile outExec dynamic extraArgs-   _ -> putStrLn result+   Just errMsg -> putStrLn errMsg+   _ -> compileHaskellFile outExec dynamic extraArgs  -- |Compile a scheme file to haskell compileSchemeFile :: Env -> String -> String -> IOThrowsError LispVal
hs-src/Interpreter/shell.hs view
@@ -16,6 +16,7 @@ import Language.Scheme.Core      -- Scheme Interpreter import Language.Scheme.Types     -- Scheme data types import Language.Scheme.Variables -- Scheme variable operations+--import Control.Monad (when) import Control.Monad.Error import System.IO import System.Environment@@ -40,19 +41,16 @@   _ <- evalString env $ "(load \"" ++ (escapeBackslashes stdlib) ++ "\")" -- Load standard library   result <- (runIOThrows $ liftM show $ evalLisp env (List [Atom "load", String (args !! 0)]))   case result of-    "" -> putStr result-    _  -> putStrLn result --  -- Call into (main) if it exists...-  alreadyDefined <- liftIO $ isBound env "main"-  let argv = List $ map String $ args-  if alreadyDefined-     then do -            mainResult <- (runIOThrows $ liftM show $ evalLisp env (List [Atom "main", List [Atom "quote", argv]]))-            case mainResult of-              "" -> putStr mainResult-              _  -> putStrLn mainResult-     else putStr "" +    Just errMsg -> putStrLn errMsg+    _  -> do +      -- Call into (main) if it exists...+      alreadyDefined <- liftIO $ isBound env "main"+      let argv = List $ map String $ args+      when alreadyDefined (do +        mainResult <- (runIOThrows $ liftM show $ evalLisp env (List [Atom "main", List [Atom "quote", argv]]))+        case mainResult of+          Just errMsg -> putStrLn errMsg+          _  -> return ())  runRepl :: IO () runRepl = do
hs-src/Language/Scheme/Compiler.hs view
@@ -7,11 +7,12 @@ Stability   : experimental Portability : portable -This module contains an experimental compiler of Scheme to Haskell +This module contains an experimental Scheme to Haskell compiler.   The compiler performs the following transformations:-Scheme AST (LispVal) -> Haskell AST (HaskAST) -> Compiled Code (String) +> Scheme AST (LispVal) => Haskell AST (HaskAST) => Compiled Code (String)+ The GHC compiler is then used to create a native executable.  At present, the focus has just been on creating a compiler that will@@ -149,7 +150,10 @@  , "main :: IO () "  , "main = do "  , "  env <- primitiveBindings "- , "  (runIOThrows $ liftM show $ run env (makeNullContinuation env) (Nil \"\") Nothing) >>= putStr "+ , "  result <- (runIOThrows $ liftM show $ run env (makeNullContinuation env) (Nil \"\") Nothing) "+ , "  case result of "+ , "    Just errMsg -> putStrLn errMsg "+ , "    _ -> return () "  , " "]  -- NOTE: the following type is used for all functions generated by the compiler: @@ -209,6 +213,10 @@ -- compile _ (List [Atom "quasiquote", val]) copts = compileScalar (" return $ " ++ astToHaskellStr val) copts +compile env args@(List [Atom "expand",  _body]) copts = do+  -- TODO: check if expand has been rebound?+  val <- Language.Scheme.Macro.expand env False _body+  compileScalar (" return $ " ++ astToHaskellStr val) copts  compile env args@(List (Atom "let-syntax" : List _bindings : _body)) copts = do   -- TODO: check if let-syntax has been rebound?
hs-src/Language/Scheme/Core.hs view
@@ -12,19 +12,20 @@  module Language.Scheme.Core     (+    -- * Scheme code evaluation       evalLisp     , evalString     , evalAndPrint-    , primitiveBindings     , apply     , continueEval--- TODO: we are starting to get some cruft here with utility functions.---       they should be relocated to a new Util module...+    -- * Core data+    , primitiveBindings+    , version+    -- * Utility functions     , escapeBackslashes     , showBanner     , substr     , updateVector-    , version     ) where import qualified Language.Scheme.FFI import qualified Language.Scheme.Macro@@ -39,9 +40,11 @@ import qualified System.Exit import System.IO +-- |husk version number version :: String-version = "3.5.3.2"+version = "3.5.4" +-- |A utility function to display the husk console banner showBanner :: IO () showBanner = do   putStrLn "  _               _        __                 _                          "@@ -81,7 +84,7 @@ @ -} evalString :: Env -> String -> IO String-evalString env expr = runIOThrows $ liftM show $ (liftThrows $ readExpr expr) >>= meval env (makeNullContinuation env)+evalString env expr = runIOThrowsREPL $ liftM show $ (liftThrows $ readExpr expr) >>= meval env (makeNullContinuation env)  -- |Evaluate a string and print results to console evalAndPrint :: Env -> String -> IO ()@@ -125,13 +128,14 @@     return val -} -{- |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- - return a result.- - -}-continueEval :: Env -> LispVal -> LispVal -> IOThrowsError LispVal+{- |A support function for eval; eval calls into this function instead of +    returning values directly. continueEval then uses the continuation +    argument to manage program control flow.+ -}+continueEval :: Env     -- ^ Current environment+             -> LispVal -- ^ Current continuation+             -> LispVal -- ^ Value of previous computation+             -> IOThrowsError LispVal -- ^ Final value of computation  {- Passing a higher-order function as the continuation; just evaluate it. This is  - done to enable an 'eval' function to be broken up into multiple sub-functions,@@ -205,11 +209,7 @@ eval env cont val@(Number _) = continueEval env cont val eval env cont val@(Bool _) = continueEval env cont val eval env cont val@(HashTable _) = continueEval env cont val-eval env cont val@(Vector _) = do-    -- TODO: Issue #35 - not good enough to just return, need to ensure only constants (?) are part-    --       of the vector-    continueEval env cont val---    throwError $ Default $ "Illegal expression (should be quoted): " ++ show val+eval env cont val@(Vector _) = continueEval env cont val eval env cont (Atom a) = continueEval env cont =<< getVar env a  -- Quote an expression by simply passing along the value@@ -302,9 +302,16 @@             _ -> cpsUnquoteList e c (head unEvaled) (Just [List (tail unEvaled), List $ acc ++ [val] ])         cpsUnquoteFld _ _ _ _ = throwError $ InternalError "Unexpected parameters to cpsUnquoteFld" +-- A special form to assist with debugging macros+eval env cont args@(List [Atom "expand" , _body]) = do+ bound <- liftIO $ isRecBound env "expand"+ if bound+  then prepareApply env cont args -- if bound to a variable in this scope; call into it+  else Language.Scheme.Macro.expand env False _body >>= continueEval env cont+  -- A rudimentary implementation of let-syntax eval env cont args@(List (Atom "let-syntax" : List _bindings : _body)) = do- bound <- liftIO $ isRecBound env "define-syntax"+ bound <- liftIO $ isRecBound env "let-syntax"  if bound   then prepareApply env cont args -- if bound to a variable in this scope; call into it   else do @@ -317,7 +324,7 @@      e -> continueEval bodyEnv cont e  eval env cont args@(List (Atom "letrec-syntax" : List _bindings : _body)) = do- bound <- liftIO $ isRecBound env "define-syntax"+ bound <- liftIO $ isRecBound env "letrec-syntax"  if bound   then prepareApply env cont args -- if bound to a variable in this scope; call into it   else do @@ -610,7 +617,7 @@ eval env cont args@(List (_ : _)) = mprepareApply env cont args eval _ _ badForm = throwError $ BadSpecialForm "Unrecognized special form" badForm --- |A helper function for the special form (string-set!)+-- |A helper function for the special form /(string-set!)/ substr :: (LispVal, LispVal, LispVal) -> IOThrowsError LispVal  substr (String str, Char char, Number ii) = do                       return $ String $ (take (fromInteger ii) . drop 0) str ++@@ -620,7 +627,7 @@ substr (String _, c, _) = throwError $ TypeMismatch "character" c substr (s, _, _) = throwError $ TypeMismatch "string" s --- |A helper function for the special form (vector-set!)+-- |A helper function for the special form /(vector-set!)/ updateVector :: LispVal -> LispVal -> LispVal -> IOThrowsError LispVal updateVector (Vector vec) (Number idx) obj = return $ Vector $ vec // [(fromInteger idx, obj)] updateVector v _ _ = throwError $ TypeMismatch "vector" v@@ -760,7 +767,7 @@  {- |Environment containing the primitive forms that are built into the Scheme language. Note that this only includes forms that are implemented in Haskell; derived forms implemented in Scheme (such as let, list, etc) are available-in the standard library which must be pulled into the environment using (load). -}+in the standard library which must be pulled into the environment using /(load)/. -} primitiveBindings :: IO Env primitiveBindings = nullEnv >>= (flip extendEnv $ map (domakeFunc IOFunc) ioPrimitives                                                ++ map (domakeFunc EvalFunc) evalFunctions
hs-src/Language/Scheme/FFI.hs view
@@ -22,7 +22,9 @@ import qualified DynFlags import qualified Unsafe.Coerce (unsafeCoerce) +-- |Load a Haskell function into husk using the GHC API. evalfuncLoadFFI :: [LispVal] -> IOThrowsError LispVal+ {-  - |Load a Haskell function into husk using the foreign function inteface (FFI)  -
hs-src/Language/Scheme/Macro.hs view
@@ -15,7 +15,7 @@   - Pattern (part of a rule that matches input) - - Transform (what the macro "expands" into)+ - Transform (what the macro expands into)   - Literal Identifiers (from the macro definition) @@ -25,26 +25,26 @@  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,+ (0) Walk the input code looking for a macro definition or macro call.+ + (1) If a macro call is found, search for a rule that matches the input.+     During this process any pattern variables in the input are loaded +     into a temporary environment - (3) Transcribe the rule's template by walking the template, inserting pattern variables -     and renaming free identifiers as needed.+ (2) If a rule matches, transcribe the rule's template by walking the +     template, inserting pattern variables and renaming free identifiers +     as needed. - (4) Walk the expanded code, checking for each of the cases from Macros That Work. If a + (3) Walk the expanded code, checking for each of the cases from Macros That Work. If a       case is found (such as a macro call or procedure abstraction) then the appropriate       handler will be called to deal with it. -}  module Language.Scheme.Macro     (-      macroEval+      expand+    , macroEval     , loadMacros  -    , expand     ) where import Language.Scheme.Types import Language.Scheme.Variables@@ -100,9 +100,13 @@ --needToExtendEnv (List [Atom "define-syntax", Atom _, (List (Atom "syntax-rules" : (List _ : _)))]) = True --needToExtendEnv _ = False  --- |macroEval---  Search for macros in the AST, and transform any that are found.-macroEval :: Env -> LispVal -> IOThrowsError LispVal+-- |Examines the input AST to see if it is a macro call. +--  If a macro call is found, the code is expanded.+--  Otherwise the input is returned unchanged.+macroEval :: Env        -- ^Current environment for the AST+          -> LispVal    -- ^AST to search+          -> IOThrowsError LispVal -- ^Transformed AST containing an+                                   -- expanded macro if found  {- Inspect code for macros  -@@ -551,9 +555,10 @@  -- |This function walks the given block of code using the macro expansion algorithm, --  recursively expanding macro calls as they are encountered.------ It is essentially a wrapper for the function walkExpanded which is internal to this module.-expand :: Env -> Bool -> LispVal -> IOThrowsError LispVal+expand :: Env       -- ^Environment of the code being expanded+       -> Bool      -- ^True if the macro was defined within another macro+       -> LispVal   -- ^Code to expand+       -> IOThrowsError LispVal -- ^Expanded code expand env dim code = do   renameEnv <- liftIO $ nullEnv   cleanupEnv <- liftIO $ nullEnv@@ -567,7 +572,7 @@    walkExpanded env env env renameEnv cleanupEnv dim True False (List []) code --- |Walk expanded code per Clinger+-- |Walk expanded code per Clinger's algorithm from Macros That Work walkExpanded :: Env -> Env -> Env -> Env -> Env -> Bool -> Bool -> Bool -> LispVal -> LispVal -> IOThrowsError LispVal walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List (List l : ls)) = do   lst <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQuoted (List []) (List l)
hs-src/Language/Scheme/Macro/Matches.hs view
@@ -40,7 +40,7 @@ -- |Get an element at given location in the nested list getData :: LispVal -- ^ The nested list to read from         -> [Int]   -- ^ Location to read an element from, all numbers are 0-based-        -> LispVal -- ^ Value read, or "Nil" if none+        -> LispVal -- ^ Value read, or 'Nil' if none getData (List lData) (i:is) = do   if length lData < i      then Nil "" -- Error: there are not enough elements in the list@@ -54,8 +54,9 @@  -- |Add an element to the given nested list setData :: LispVal -- ^ The nested list to modify-        -> [Int]   -- ^ Location to insert the new element, from top-most -> leaf -                   --   (EG: [1, 2] means add to the second top-most list, at its 3rd position)+        -> [Int]   -- ^ Location to insert the new element, from top-most to the leaf.+                   --   For example [1, 2] means add to the second top-most list, at+                   --   its 3rd position.         -> LispVal -- ^ Value to insert          -> LispVal -- ^ Resulant list setData (List lData) (i:is) val = do
hs-src/Language/Scheme/Numerical.hs view
@@ -10,11 +10,58 @@ This module implements the numerical tower. -} -module Language.Scheme.Numerical where+module Language.Scheme.Numerical (+   numericBinop+-- , foldlM+-- , foldl1M+ , numSub+ , numMul+ , numDiv+ , numAdd+ , numBoolBinopEq+ , numBoolBinopGt+ , numBoolBinopGte+ , numBoolBinopLt+ , numBoolBinopLte+ , numCast+ , numFloor+ , numCeiling+ , numTruncate+ , numRound+ , numSin+ , numCos+ , numTan+ , numAsin + , numAcos+ , numAtan+ , numExpt+ , numSqrt+ , numExp+ , numLog+ , buildComplex+ , numMakePolar+ , numRealPart+ , numImagPart+ , numMagnitude+ , numAngle+ , numMakeRectangular+ , numDenominator+ , numNumerator+ , numInexact2Exact+ , numExact2Inexact + , num2String+ , isComplex+ , isReal + , isRational+ , isInteger+ , isNumber+ , isFloatAnInteger+ , unpackNum+) where import Language.Scheme.Types import Data.Complex import Control.Monad.Error-import Data.Char+import Data.Char hiding (isNumber) import Numeric import Data.Ratio import Text.Printf@@ -355,7 +402,7 @@ numInexact2Exact [badType] = throwError $ TypeMismatch "number" badType numInexact2Exact badArgList = throwError $ NumArgs 1 badArgList --- Convert a number to a string; radix is optional, defaults to base 10+-- |Convert a number to a string; radix is optional, defaults to base 10 num2String :: [LispVal] -> ThrowsError LispVal num2String [(Number n)] = return $ String $ show n num2String [(Number n), (Number radix)] = do@@ -407,13 +454,16 @@ isInteger ([n@(Float _)]) = return $ Bool $ isFloatAnInteger n isInteger _ = return $ Bool False +-- |A utility function to determine if given value is a floating point+--  number representing an whole number (integer). isFloatAnInteger :: LispVal -> Bool isFloatAnInteger (Float n) = (floor n) == (ceiling n) isFloatAnInteger _ = False  -- - end Numeric operations section --- -+-- |Extract an integer from the given value, throwing a type error if+--  the wrong type is passed. unpackNum :: LispVal -> ThrowsError Integer unpackNum (Number n) = return n unpackNum notNum = throwError $ TypeMismatch "number" notNum
hs-src/Language/Scheme/Parser.hs view
@@ -11,7 +11,38 @@ This module implements parsing of Scheme code. -} -module Language.Scheme.Parser where+module Language.Scheme.Parser +    (+      lispDef+    -- *Higher level parsing+    , mainParser+    , readOrThrow+    , readExpr+    , readExprList +    -- *Low level parsing+    , symbol+    , parseExpr +    , parseAtom+    , parseBool+    , parseChar+    , parseOctalNumber +    , parseBinaryNumber+    , parseHexNumber+    , parseDecimalNumber+    , parseNumber +    , parseRealNumber+    , parseRationalNumber +    , parseComplexNumber +    , parseEscapedChar +    , parseString +    , parseVector+    , parseList+    , parseDottedList+    , parseQuoted+    , parseQuasiQuoted +    , parseUnquoted +    , parseUnquoteSpliced +    )where import Language.Scheme.Types import Control.Monad.Error import qualified Data.Char as Char@@ -23,15 +54,16 @@ import Text.Parsec.Language import Text.Parsec.Prim (ParsecT) import qualified Text.Parsec.Token as P+ -- This was added by pull request #63 as part of a series of fixes -- to get husk to build on ghc 7.2.2 -- -- For now this has been removed to allow husk to support the older--- GHC 6.x.x series. But if removing this breaks things on 7.2 then --- it will force a "real" solution...+-- GHC 6.x.x series. -- --import Data.Functor.Identity (Identity) +-- |Language definition for Scheme lispDef :: LanguageDef () lispDef    = emptyDef    @@ -54,6 +86,8 @@ --parens :: ParsecT String () Identity a -> ParsecT String () Identity a parens = P.parens lexer +brackets = P.brackets lexer+ --identifier :: ParsecT String () Identity String identifier = P.identifier lexer @@ -140,8 +174,7 @@               parseOctalNumber <?>               "Unable to parse number" -{- Parser for floating points- - -}+-- |Parser a floating point number parseRealNumber :: Parser LispVal parseRealNumber = do   sign <- many (oneOf "-+")@@ -282,6 +315,7 @@   x <- parseExpr   return $ List [Atom "unquote-splicing", x] +-- |Parse an expression parseExpr :: Parser LispVal parseExpr =       try (lexeme parseComplexNumber)@@ -302,6 +336,8 @@   <|> parseUnquoted   <|> try (parens parseList)   <|> parens parseDottedList+  <|> try (brackets parseList)+  <|> brackets parseDottedList   <?> "Expression"  mainParser :: Parser LispVal@@ -311,14 +347,18 @@ -- FUTURE? (seemed to break test cases, but is supposed to be best practice?)    eof     return x +-- |Use a parser to parse the given text, throwing an error+--  if there is a problem parsing the text. readOrThrow :: Parser a -> String -> ThrowsError a readOrThrow parser input = case parse parser "lisp" input of   Left err -> throwError $ Parser err   Right val -> return val +-- |Parse an expression from a string of text readExpr :: String -> ThrowsError LispVal readExpr = readOrThrow mainParser +-- |Parse many expressions from a string of text readExprList :: String -> ThrowsError [LispVal] readExprList = readOrThrow (endBy mainParser whiteSpace) 
hs-src/Language/Scheme/Primitives.hs view
@@ -1,3 +1,5 @@+{-# Language ExistentialQuantification #-}+ {- | Module      : Language.Scheme.Primitives Copyright   : Justin Ethier@@ -7,15 +9,97 @@ Stability   : experimental Portability : portable -This module contains Primitive functions written in Haskell.+This module contains primitive functions written in Haskell.+Most of these map directly to an equivalent Scheme function.+ -} -module Language.Scheme.Primitives where+module Language.Scheme.Primitives (+ -- * Pure functions+ -- ** List+   car+ , cdr + , cons+ , equal + -- ** Vector+ , buildVector + , vectorLength + , vectorRef + , vectorToList + , listToVector+ , makeVector+ -- ** Hash Table+ , hashTblExists + , hashTblRef+ , hashTblSize + , hashTbl2List+ , hashTblKeys+ , hashTblValues + , hashTblCopy+ , hashTblMake+ -- ** String+ , buildString+ , makeString+ , doMakeString+ , stringLength+ , stringRef+ , substring+ , stringCIEquals + , stringCIBoolBinop + , stringAppend + , stringToNumber+ , stringToList + , listToString+ , stringCopy + , symbol2String + , string2Symbol+ --data Unpacker = forall a . Eq a => AnyUnpacker (LispVal -> ThrowsError a)+ -- ** Predicate+ , isHashTbl+ , isChar + , isString + , isBoolean + , isDottedList + , isProcedure + , isList + , isVector + , isNull + , isEOFObject + , isSymbol + -- ** Utility functions+ , unpackEquals + , boolBinop + , unaryOp + , strBoolBinop + , boolBoolBinop+ , unpackStr + , unpackBool+ -- * Impure functions+ -- |All of these functions must be executed within the IO monad.+ + -- ** Input / Output + , makePort + , closePort+ , currentOutputPort + , currentInputPort + , isOutputPort + , isInputPort+ , readProc + , readCharProc + , writeProc + , writeCharProc+ , readContents+ , load+ , readAll+ -- ** Symbol generation+ , gensym+ , _gensym+ ) where import Language.Scheme.Numerical import Language.Scheme.Parser import Language.Scheme.Types import Control.Monad.Error-import Data.Char+import Data.Char hiding (isSymbol) import Data.Array import Data.Unique import qualified Data.Map@@ -118,13 +202,14 @@ readAll [] = throwError $ NumArgs 1 [] readAll args@(_ : _) = throwError $ NumArgs 1 args --- Version of gensym that can be conveniently called from Haskell+-- |Version of gensym that can be conveniently called from Haskell. _gensym :: String -> IOThrowsError LispVal _gensym prefix = do     u <- liftIO $ newUnique     return $ Atom $ prefix ++ (show $ Number $ toInteger $ hashUnique u) --- Non-standard function, generate a (reasonably) unique symbol given an optional prefix+-- |Generate a (reasonably) unique symbol, given an optional prefix.+--  This function is provided even though it is not part of R5RS. gensym :: [LispVal] -> IOThrowsError LispVal gensym [String prefix] = _gensym prefix gensym [] = _gensym " g"
hs-src/Language/Scheme/Types.hs view
@@ -11,7 +11,39 @@  -} -module Language.Scheme.Types where+module Language.Scheme.Types+{-    (+      Env+--    , Environment+    , parentEnv+    , bindings+    , nullEnv +    , macroNamespace+    , varNamespace+    , LispError+    , ThrowsError +    , trapError+    , extractValue +    , IOThrowsError +    , liftThrows +    , runIOThrowsREPL +    , runIOThrows +    , LispVal+    , DeferredCode+    , DynamicWinders   +    , before +    , after +    , showDWVal +    , makeNullContinuation +    , makeCPS +    , makeCPSWArgs +    , eqv +    , eqvList+    , eqVal +    , showVal+    , unwordsList+    ) -}+ where import Data.Complex import Control.Monad.Error import Data.Array@@ -92,8 +124,19 @@ liftThrows (Left err) = throwError err liftThrows (Right val) = return val -runIOThrows :: IOThrowsError String -> IO String-runIOThrows action = runErrorT (trapError action) >>= return . extractValue+-- |Execute an IO action and return result or an error message.+--  This is intended for use by a REPL, where a result is always+--  needed regardless of type.+runIOThrowsREPL :: IOThrowsError String -> IO String+runIOThrowsREPL action = runErrorT (trapError action) >>= return . extractValue++-- |Execute an IO action and return error or Nothing if no error was thrown.+runIOThrows :: IOThrowsError String -> IO (Maybe String)+runIOThrows action = do+    runState <- runErrorT action+    case runState of+        Left err -> return $ Just (show err)+        Right _ -> return $ Nothing  -- |Scheme data types data LispVal = Atom String
hs-src/Language/Scheme/Variables.hs view
@@ -7,11 +7,32 @@ Stability   : experimental Portability : portable -This module contains code for working with Scheme variables.+This module contains code for working with Scheme variables,+and the environments that contain them.  -} -module Language.Scheme.Variables where+module Language.Scheme.Variables +    (+    -- * Environments+      printEnv+    , copyEnv+    , extendEnv+    , findNamespacedEnv+    -- * Getters+    , getVar+    , getNamespacedVar +    -- * Setters+    , defineVar+    , setVar+    , setNamespacedVar+    , defineNamespacedVar+    -- * Predicates+    , isBound+    , isRecBound+    , isNamespacedBound+    , isNamespacedRecBound +    ) where import Language.Scheme.Types import Control.Monad.Error import Data.IORef@@ -51,7 +72,8 @@ -}  -- |Show the contents of an environment-printEnv :: Env -> IO String+printEnv :: Env         -- ^Environment+         -> IO String   -- ^Contents of the env as a string printEnv env = do   binds <- liftIO $ readIORef $ bindings env   l <- mapM showVar $ Data.Map.toList binds @@ -62,7 +84,8 @@     return $ name ++ ": " ++ show v  -- |Create a deep copy of an environment-copyEnv :: Env -> IO Env+copyEnv :: Env      -- ^ Source environment+        -> IO Env   -- ^ A copy of the source environment copyEnv env = do   binds <- liftIO $ readIORef $ bindings env --  bindingList <- mapM addBinding binds >>= newIORef@@ -77,15 +100,22 @@ -- |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 :: Env -- ^ Environment +          -> [((String, String), LispVal)] -- ^ Extensions to the environment+          -> IO Env -- ^ Extended environment 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) --- Recursively search environments to find one that contains var-findNamespacedEnv :: Env -> String -> String -> IO (Maybe Env)+-- |Recursively search environments to find one that contains the given variable.+findNamespacedEnv +    :: Env      -- ^Environment to begin the search; +                --  parent env's will be searched as well.+    -> String   -- ^Namespace+    -> String   -- ^Variable+    -> IO (Maybe Env) -- ^Environment, or Nothing if there was no match. findNamespacedEnv envRef namespace var = do   found <- liftIO $ isNamespacedBound envRef namespace var   if found@@ -95,20 +125,34 @@                Nothing -> return Nothing  -- |Determine if a variable is bound in the default namespace-isBound :: Env -> String -> IO Bool+isBound :: Env      -- ^ Environment+        -> String   -- ^ Variable+        -> IO Bool  -- ^ True if the variable is bound isBound envRef var = isNamespacedBound envRef varNamespace var --- |Determine if a variable is bound in the default namespace, in this env or a parent-isRecBound :: Env -> String -> IO Bool+-- |Determine if a variable is bound in the default namespace, +--  in this environment or one of its parents.+isRecBound :: Env      -- ^ Environment+           -> String   -- ^ Variable+           -> IO Bool  -- ^ True if the variable is bound isRecBound envRef var = isNamespacedRecBound envRef varNamespace var  -- |Determine if a variable is bound in a given namespace-isNamespacedBound :: Env -> String -> String -> IO Bool+isNamespacedBound +    :: Env      -- ^ Environment+    -> String   -- ^ Namespace+    -> String   -- ^ Variable+    -> IO Bool  -- ^ True if the variable is bound 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+-- |Determine if a variable is bound in a given namespace+--  or a parent of the given environment.+isNamespacedRecBound +    :: Env      -- ^ Environment+    -> String   -- ^ Namespace+    -> String   -- ^ Variable+    -> IO Bool  -- ^ True if the variable is bound isNamespacedRecBound envRef namespace var = do   env <- findNamespacedEnv envRef namespace var   case env of@@ -116,11 +160,16 @@     Nothing -> return False  -- |Retrieve the value of a variable defined in the default namespace-getVar :: Env -> String -> IOThrowsError LispVal+getVar :: Env       -- ^ Environment+       -> String    -- ^ Variable+       -> IOThrowsError LispVal -- ^ Contents of the variable getVar envRef var = getNamespacedVar envRef varNamespace var  -- |Retrieve the value of a variable defined in a given namespace-getNamespacedVar :: Env -> String -> String -> IOThrowsError LispVal+getNamespacedVar :: Env     -- ^ Environment+                 -> String  -- ^ Namespace+                 -> String  -- ^ Variable+                 -> IOThrowsError LispVal -- ^ Contents of the variable getNamespacedVar envRef                  namespace                  var = do binds <- liftIO $ readIORef $ bindings envRef@@ -132,14 +181,28 @@   -- |Set a variable in the default namespace-setVar, defineVar :: Env -> String -> LispVal -> IOThrowsError LispVal+setVar+    :: Env      -- ^ Environment+    -> String   -- ^ Variable+    -> LispVal  -- ^ Value+    -> IOThrowsError LispVal -- ^ Value setVar envRef var value = setNamespacedVar envRef varNamespace var value --- ^Bind a variable in the default namespace+-- |Bind a variable in the default namespace+defineVar+    :: Env      -- ^ Environment+    -> String   -- ^ Variable+    -> LispVal  -- ^ Value+    -> IOThrowsError LispVal -- ^ Value defineVar envRef var value = defineNamespacedVar envRef varNamespace var value  -- |Set a variable in a given namespace-setNamespacedVar :: Env -> String -> String -> LispVal -> IOThrowsError LispVal+setNamespacedVar +    :: Env      -- ^ Environment +    -> String   -- ^ Namespace+    -> String   -- ^ Variable+    -> LispVal  -- ^ Value+    -> IOThrowsError LispVal   -- ^ Value setNamespacedVar envRef                  namespace                  var value = do env <- liftIO $ readIORef $ bindings envRef@@ -152,7 +215,12 @@                                               Nothing -> throwError $ UnboundVar "Setting an unbound variable: " var  -- |Bind a variable in the given namespace-defineNamespacedVar :: Env -> String -> String -> LispVal -> IOThrowsError LispVal+defineNamespacedVar+    :: Env      -- ^ Environment +    -> String   -- ^ Namespace+    -> String   -- ^ Variable+    -> LispVal  -- ^ Value+    -> IOThrowsError LispVal   -- ^ Value defineNamespacedVar envRef                     namespace                     var value = do
husk-scheme.cabal view
@@ -1,5 +1,5 @@ Name:                husk-scheme-Version:             3.5.3.2+Version:             3.5.4 Synopsis:            R5RS Scheme interpreter, compiler, and library. Description:         A dialect of R5RS Scheme written in Haskell. Provides advanced                       features including continuations, hygienic macros, a Haskell FFI,@@ -24,7 +24,7 @@  Library   Build-Depends:   base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory, ghc, ghc-paths-  Extensions:      ExistentialQuantification CPP CPP+  Extensions:      ExistentialQuantification   Hs-Source-Dirs:  hs-src   Exposed-Modules: Language.Scheme.Core                    Language.Scheme.Types@@ -41,12 +41,12 @@  Executable         huski   Build-Depends:   husk-scheme, base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory, ghc, ghc-paths-  Extensions:      ExistentialQuantification CPP CPP+  Extensions:      ExistentialQuantification   Main-is:         shell.hs   Hs-Source-Dirs:  hs-src/Interpreter  Executable huskc   Build-Depends: husk-scheme, base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory, ghc, ghc-paths, process, filepath-  Extensions: ExistentialQuantification CPP CPP+  Extensions:      ExistentialQuantification   Main-is: huskc.hs   Hs-Source-Dirs: hs-src/Compiler