packages feed

husk-scheme 3.6.2 → 3.6.3

raw patch · 12 files changed

+592/−68 lines, 12 filesdep +bytestringdep +utf8-stringPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: bytestring, utf8-string

API changes (from Hackage documentation)

- Language.Scheme.Parser: symbol :: Parser Char
- Language.Scheme.Types: NotFunction :: String -> String -> LispError
+ Language.Scheme.Core: evalLisp' :: Env -> LispVal -> IO (ThrowsError LispVal)
+ Language.Scheme.Core: updateByteVector :: LispVal -> LispVal -> LispVal -> IOThrowsError LispVal
+ Language.Scheme.Parser: parseByteVector :: Parser LispVal
+ Language.Scheme.Primitives: byteVector :: [LispVal] -> ThrowsError LispVal
+ Language.Scheme.Primitives: byteVectorAppend :: [LispVal] -> ThrowsError LispVal
+ Language.Scheme.Primitives: byteVectorCopy :: [LispVal] -> ThrowsError LispVal
+ Language.Scheme.Primitives: byteVectorLength :: [LispVal] -> ThrowsError LispVal
+ Language.Scheme.Primitives: byteVectorRef :: [LispVal] -> ThrowsError LispVal
+ Language.Scheme.Primitives: byteVectorStr2Utf :: [LispVal] -> ThrowsError LispVal
+ Language.Scheme.Primitives: byteVectorUtf2Str :: [LispVal] -> ThrowsError LispVal
+ Language.Scheme.Primitives: isByteVector :: LispVal -> ThrowsError LispVal
+ Language.Scheme.Primitives: makeByteVector :: [LispVal] -> ThrowsError LispVal
+ Language.Scheme.Types: ByteVector :: ByteString -> LispVal
+ Language.Scheme.Variables: topmostEnv :: Env -> IO Env

Files

ChangeLog.markdown view
@@ -1,3 +1,25 @@+v3.6.3+--------++Added support for R<sup>7</sup>RS bytevectors.++Added the Haskell function `evalLisp'` to evaluate a lisp data structure and return the `LispVal` or `LispError` result directly:++    evalLisp' :: Env -> LispVal -> IO (ThrowsError LispVal)++This makes it much easier to retrieve results when using husk as an extension language:++    result <- evalLisp' env $ List [Atom "/", Number 1, Number 0]+    case result of+      Left err -> putStrLn $ "Error: " ++ (show err)+      Right val -> putStrLn $ show val++Fixed a bug where setting a variable to refer back to itself would result in an infinite loop. For example, the last line of the following code would cause `huski` to hang:++    (define a '())+    (define b a)+    (define a b)+ v3.6.2 -------- This release adds support for nested quasi-quotation forms, which now respect depth level. This was done by replacing the quasi-quotation special form with a macro based on the one from chibi scheme. A nice side-benefit is that by removing the special forms, quasi-quotation now works in the compiler.
README.markdown view
@@ -15,6 +15,26 @@     cabal update     cabal install husk-scheme +Before running husk you may also need to add the cabal executable directory to your path. On Linux this is `~/.cabal/bin`. Now you are ready to start up the interpreter:++    justin@my-pc$ huski+      _               _        __                 _                          +     | |             | |       \\\               | |                         +     | |__  _   _ ___| | __     \\\      ___  ___| |__   ___ _ __ ___   ___  +     | '_ \| | | / __| |/ /    //\\\    / __|/ __| '_ \ / _ \ '_ ` _ \ / _ \ +     | | | | |_| \__ \   <    /// \\\   \__ \ (__| | | |  __/ | | | | |  __/ +     |_| |_|\__,_|___/_|\_\  ///   \\\  |___/\___|_| |_|\___|_| |_| |_|\___| +                                                                             +     http://justinethier.github.com/husk-scheme                              +     (c) 2010-2012 Justin Ethier                                             +     Version 3.6.2 +                                                                             +    huski> (define (hello) 'world)+    (lambda () ...)+    huski> (hello)+    world+    huski>+ husk has been tested on Windows, Linux, and FreeBSD.  More information is available on the [husk website](http://justinethier.github.com/husk-scheme).
hs-src/Language/Scheme/Compiler.hs view
@@ -22,18 +22,20 @@ -}  module Language.Scheme.Compiler where -import qualified Language.Scheme.Core (apply, escapeBackslashes)+import qualified Language.Scheme.Core (apply, escapeBackslashes, evalLisp) import qualified Language.Scheme.Macro import Language.Scheme.Primitives import Language.Scheme.Types import Language.Scheme.Variables import Control.Monad.Error import qualified Data.Array+import qualified Data.ByteString as BS import Data.Complex import qualified Data.List import qualified Data.Map import Data.Ratio---import Debug.Trace+import Data.Word+-- import Debug.Trace  -- A type to store options passed to compile -- eventually all of this might be able to be integrated into a Compile monad@@ -110,6 +112,9 @@   let ls = Data.Array.elems v       size = (length ls) - 1   "Vector (listArray (0, " ++ show size ++ ")" ++ "[" ++ joinL (map ast2Str ls) "," ++ "])"+ast2Str (ByteVector bv) = do+  let ls = BS.unpack bv+  "ByteVector ( BS.pack " ++ "[" ++ joinL (map show ls) "," ++ "])" ast2Str (List ls) = "List [" ++ joinL (map ast2Str ls) "," ++ "]" ast2Str (DottedList ls l) =    "DottedList [" ++ joinL (map ast2Str ls) "," ++ "] $ " ++ ast2Str l@@ -129,9 +134,11 @@  , "Language.Scheme.Variables -- Scheme variable operations "  , "Control.Monad.Error "  , "Data.Array "+ , " qualified Data.ByteString as BS "  , "Data.Complex "  , " qualified Data.Map "  , "Data.Ratio "+ , "Data.Word "  , "System.IO "]  header :: String -> [String]@@ -209,6 +216,7 @@ compile _ (Bool b) copts = compileScalar ("  return $ Bool " ++ (show b)) copts -- TODO: eval env cont val@(HashTable _) = continueEval env cont val compile _ v@(Vector _) copts = compileScalar (" return $ " ++ ast2Str v) copts+compile _ v@(ByteVector _) copts = compileScalar (" return $ " ++ ast2Str v) copts compile _ ht@(HashTable _) copts = compileScalar (" return $ " ++ ast2Str ht) copts compile _ (Atom a) copts = do  c <- return $ createAstCont copts "val" ""@@ -219,6 +227,7 @@    AstValue $ "    DottedList _ _ -> Pointer \"" ++ a ++ "\" env",    AstValue $ "    String _ -> Pointer \"" ++ a ++ "\" env",    AstValue $ "    Vector _ -> Pointer \"" ++ a ++ "\" env",+   AstValue $ "    ByteVector _ -> Pointer \"" ++ a ++ "\" env",    AstValue $ "    HashTable _ -> Pointer \"" ++ a ++ "\" env",    AstValue $ "    _ -> v"], c] @@ -605,6 +614,30 @@ -- TODO: eval env cont args@(List [Atom "vector-set!" , nonvar , _ , _]) = do  -- TODO: eval env cont fargs@(List (Atom "vector-set!" : args)) = do  +compile env (List [Atom "bytevector-u8-set!", Atom var, i, object]) copts = do+ Atom symCompiledIdx <- _gensym "bytevectorSetIdx"+ Atom symCompiledObj <- _gensym "bytevectorSetObj"+ Atom symUpdateVec <- _gensym "bytevectorSetUpdate"+ Atom symIdxWrapper <- _gensym "bytevectorSetIdxWrapper"++ -- Entry point that allows this form to be redefined+ entryPt <- compileSpecialFormEntryPoint "bytevector-u8-set!" symCompiledIdx copts+ -- Compile index, then use a wrapper to pass it as an arg while compiling obj+ compiledIdx <- compileExpr env i symCompiledIdx (Just symIdxWrapper) + compiledIdxWrapper <- return $ AstFunction symIdxWrapper " env cont idx _ " [+    AstValue $ "  " ++ symCompiledObj ++ " env (makeCPSWArgs env cont " ++ symUpdateVec ++ " [idx]) (Nil \"\") Nothing " ]+ compiledObj <- compileExpr env object symCompiledObj Nothing+ -- Do actual update+ compiledUpdate <- return $ AstFunction symUpdateVec " env cont obj (Just [idx]) " [+    AstValue $ "  vec <- getVar env \"" ++ var ++ "\"",+    AstValue $ "  result <- updateByteVector vec idx obj >>= updateObject env \"" ++ var ++ "\"",+    createAstCont copts "result" ""]++ return $ [entryPt, compiledIdxWrapper, compiledUpdate] ++ compiledIdx ++ compiledObj++-- TODO: eval env cont args@(List [Atom "bytevector-u8-set!" , nonvar , _ , _]) = do +-- TODO: eval env cont fargs@(List (Atom "bytevector-u8-set!" : args)) = do + compile env (List [Atom "hash-table-set!", Atom var, rkey, rvalue]) copts = do  Atom symCompiledIdx <- _gensym "hashTableSetIdx"  Atom symCompiledObj <- _gensym "hashTableSetObj"@@ -648,6 +681,32 @@   return $ [entryPt, compiledUpdate] ++ compiledIdx -- TODO: eval env cont fargs@(List (Atom "hash-table-delete!" : args)) = do++-- TODO:+-- Testing this out; idea is to compile-in any code injected via load+compile env (List [Atom "load", filename, envSpec]) copts = do+  -- More TODO:+  -- Hacking around, the issue with require-extension / and-let* is that+  -- the compiler loads (and-let*) and attempts to compile the argument+  -- () which cannot be evaluated, hence the special form error on ()+  --+  -- LispEnv env+  y <- Language.Scheme.Core.evalLisp env envSpec+  -- TODO: I think this is no good because current-environment is really the+  -- same as env here. it would need to be evaluated and stored when it is first found+  -- hmm...not quite sure how to proceed here, need to think on it+  LispEnv env' <- Language.Scheme.Core.evalLisp env y+  compile env' (List [Atom "load", filename]) copts+compile env (List [Atom "load", Atom filename]) copts = do+  String filename' <- getVar env filename+  compile env (List [Atom "load", String filename']) copts+compile env (List [Atom "load", String filename]) copts = do -- TODO: allow filename from a var, support env optional arg+ Atom symEntryPt <- _gensym "load"+ result <- compileLisp env filename symEntryPt Nothing+ return $ result ++ +   [createAstFunc copts [+    AstValue $ "  result <- " ++ symEntryPt ++ " env (makeNullContinuation env) (Nil \"\") Nothing",+    createAstCont copts "result" ""]]  -- FUTURE: eventually it should be possible to evaluate the args instead of assuming -- that they are all strings, but lets keep it simple for now
hs-src/Language/Scheme/Core.hs view
@@ -16,6 +16,7 @@     (     -- * Scheme code evaluation       evalLisp+    , evalLisp'     , evalString     , evalAndPrint     , apply@@ -29,6 +30,7 @@     , showBanner     , substr     , updateVector+    , updateByteVector     ) where #ifdef UseFfi import qualified Language.Scheme.FFI@@ -41,15 +43,17 @@ import Language.Scheme.Variables import Control.Monad.Error import Data.Array+import qualified Data.ByteString as BS import qualified Data.Char import qualified Data.Map+import Data.Word import qualified System.Exit import System.IO--- import Debug.Trace+import Debug.Trace  -- |husk version number version :: String-version = "3.6.2"+version = "3.6.3"  -- |A utility function to display the husk console banner showBanner :: IO ()@@ -62,7 +66,7 @@   putStrLn " |_| |_|\\__,_|___/_|\\_\\  ///   \\\\\\  |___/\\___|_| |_|\\___|_| |_| |_|\\___| "   putStrLn "                                                                         "   putStrLn " http://justinethier.github.com/husk-scheme                              "-  putStrLn " (c) 2010-2012 Justin Ethier                                             "+  putStrLn " (c) 2010-2013 Justin Ethier                                             "   putStrLn $ " Version " ++ version ++ " "   putStrLn "                                                                         " @@ -88,9 +92,7 @@                    | otherwise =  x : xs   -{- |Evaluate a string containing Scheme code.--    For example:+{- |Evaluate a string containing Scheme code  @ env <- primitiveBindings@@ -113,12 +115,24 @@ evalAndPrint :: Env -> String -> IO () evalAndPrint env expr = evalString env expr >>= putStrLn --- |Evaluate lisp code that has already been loaded into haskell+-- |Evaluate a lisp data structure and return a value for use by husk evalLisp :: Env -> LispVal -> IOThrowsError LispVal evalLisp env lisp = do   v <- meval env (makeNullContinuation env) lisp   recDerefPtrs v +-- |Evaluate a lisp data structure and return the LispVal or LispError+--  result directly+-- +-- @+--  result <- evalLisp' env $ List [Atom "/", Number 1, Number 0]+--  case result of+--    Left err -> putStrLn $ "Error: " ++ (show err)+--    Right val -> putStrLn $ show val+-- @+evalLisp' :: Env -> LispVal -> IO (ThrowsError LispVal)+evalLisp' env lisp = runErrorT (evalLisp env lisp)+ -- |A wrapper for macroEval and eval meval, mprepareApply :: Env -> LispVal -> LispVal -> IOThrowsError LispVal meval env cont lisp = mfunc env cont lisp eval@@ -235,6 +249,7 @@ eval env cont val@(Bool _) = continueEval env cont val eval env cont val@(HashTable _) = continueEval env cont val eval env cont val@(Vector _) = continueEval env cont val+eval env cont val@(ByteVector _) = continueEval env cont val eval env cont val@(Pointer _ _) = continueEval env cont val eval env cont (Atom a) = do   v <- getVar env a@@ -244,6 +259,7 @@     DottedList _ _ -> Pointer a env     String _ -> Pointer a env     Vector _ -> Pointer a env+    ByteVector _ -> Pointer a env     HashTable _ -> Pointer a env #endif     _ -> v@@ -538,6 +554,35 @@   then prepareApply env cont fargs -- if is bound to a variable in this scope; call into it   else throwError $ NumArgs 3 args +eval env cont args@(List [Atom "bytevector-u8-set!", Atom var, i, object]) = do+ bound <- liftIO $ isRecBound env "bytevector-u8-set!"+ if bound+  then prepareApply env cont args -- if is bound to a variable in this scope; call into it+  else meval env (makeCPS env cont cpsObj) i+ where+        cpsObj :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal+        cpsObj e c idx _ = meval e (makeCPSWArgs e c cpsVec $ [idx]) object++        cpsVec :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal+        cpsVec e c obj (Just [idx]) = (meval e (makeCPSWArgs e c cpsUpdateVec $ [idx, obj]) =<< getVar e var)+        cpsVec _ _ _ _ = throwError $ InternalError "Invalid argument to cpsVec"++        cpsUpdateVec :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal+        cpsUpdateVec e c vec (Just [idx, obj]) =+            updateByteVector vec idx obj >>= updateObject e var >>= continueEval e c+        cpsUpdateVec _ _ _ _ = throwError $ InternalError "Invalid argument to cpsUpdateVec"++eval env cont args@(List [Atom "bytevector-u8-set!" , nonvar , _ , _]) = do + bound <- liftIO $ isRecBound env "bytevector-u8-set!"+ if bound+  then prepareApply env cont args -- if is bound to a variable in this scope; call into it+  else throwError $ TypeMismatch "variable" nonvar+eval env cont fargs@(List (Atom "bytevector-u8-set!" : args)) = do + bound <- liftIO $ isRecBound env "bytevector-u8-set!"+ if bound+  then prepareApply env cont fargs -- if is bound to a variable in this scope; call into it+  else throwError $ NumArgs 3 args+ eval env cont args@(List [Atom "hash-table-set!", Atom var, rkey, rvalue]) = do  bound <- liftIO $ isRecBound env "hash-table-set!"  if bound@@ -623,6 +668,20 @@   updateVector vec i obj updateVector v _ _ = throwError $ TypeMismatch "vector" v +-- |A helper function for the special form /(bytevector-u8-set!)/+updateByteVector :: LispVal -> LispVal -> LispVal -> IOThrowsError LispVal+updateByteVector (ByteVector vec) (Number idx) obj = +    case obj of+        Number byte -> do+-- TODO: error checking+           let (h, t) = BS.splitAt (fromInteger idx) vec+           return $ ByteVector $ BS.concat [h, BS.pack $ [fromInteger byte :: Word8], BS.tail t]+        badType -> throwError $ TypeMismatch "byte" badType+updateByteVector ptr@(Pointer _ _) i obj = do+  vec <- recDerefPtrs ptr+  updateByteVector vec i obj+updateByteVector v _ _ = throwError $ TypeMismatch "bytevector" v+ {- Prepare for apply by evaluating each function argument,    and then execute the function via 'apply' -} prepareApply :: Env -> LispVal -> LispVal -> IOThrowsError LispVal@@ -654,7 +713,10 @@ prepareApply _ _ _ = throwError $ Default "Unexpected error in prepareApply"  -- |Call into a Scheme function-apply :: LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal+apply :: LispVal  -- ^ Current continuation+      -> LispVal  -- ^ Function or continuation to execute+      -> [LispVal] -- ^ Arguments+      -> IOThrowsError LispVal -- ^ Final value of computation apply _ cont@(Continuation env ccont ncont _ ndynwind) args = do -- case (trace ("calling into continuation. dynWind = " ++ show ndynwind) ndynwind) of   case ndynwind of@@ -764,7 +826,7 @@ -- evalfuncExitSuccess, evalfuncExitFail, evalfuncApply, evalfuncDynamicWind,    evalfuncEval, evalfuncLoad, evalfuncCallCC, evalfuncCallWValues,-  evalfuncMakeEnv, evalfuncNullEnv, evalfuncInteractionEnv :: [LispVal] -> IOThrowsError LispVal+  evalfuncMakeEnv, evalfuncNullEnv, evalfuncInteractionEnv, evalfuncImport :: [LispVal] -> IOThrowsError LispVal  {-  - A (somewhat) simplified implementation of dynamic-wind@@ -841,6 +903,61 @@ evalfuncInteractionEnv (cont@(Continuation env _ _ _ _) : _) = do     continueEval env cont $ LispEnv env +-- TODO: just testing out a binding for %import+-- evalfuncImport [+--     cont@(Continuation env _ _ _ _), +--     LispEnv toEnv,+--     LispEnv fromEnv, +--     List imports,+--     _] = do+-- --    topmostEnv <- liftIO $ topmostEnv toEnv -- TODO: testing this out; trying to overcome introducing vars to a nested env+--     LispEnv toEnv' <- getVar toEnv "meta-env"+--     result <- moduleImport toEnv' fromEnv imports+--     continueEval env cont (trace ("finished import") result)+-- +-- evalfuncImport [+--     cont@(Continuation env a b c d), +--     Bool False, -- Default to env+--     LispEnv fromEnv, +--     List imports,+--     _] = do+-- --    topmostEnv <- liftIO $ topmostEnv env -- TODO: testing this out; trying to overcome introducing vars to a nested env+--     LispEnv toEnv <- getVar env "meta-env"+--     LispEnv env' <- moduleImport toEnv fromEnv imports+--     continueEval+--         env'+--         (Continuation env' a b c d)+--         (trace ("finished import 2") $ LispEnv env')+-- -- TODO: should env' be passed along?    continueEval env' cont (trace ("finished import") $ LispEnv env')++evalfuncImport [+    cont@(Continuation env _ _ _ _), +    toEnv,+    LispEnv fromEnv, +    imports,+    _] = do+    let sourceEnv = case toEnv of+                        LispEnv e -> e+                        Bool False -> env++    LispEnv toEnv' <- getVar sourceEnv "meta-env"+    case imports of+        List i -> do+            result <- moduleImport toEnv' fromEnv i+            continueEval env cont (trace ("finished import") result)+-- TODO:        Bool False -> do -- Export everything (?)++-- This is just for debugging purposes:+evalfuncImport (cont@(Continuation env _ _ _ _ ) : cs) = do+    (trace ("import DEBUG: " ++ show cs) continueEval) env cont $ Nil ""++moduleImport to from (Atom i : is) = do+  v <- getVar from i +  _ <- defineVar to i (trace ("Import toEnv: " ++ "[" ++ i ++ "]" ++ show v) v)+  moduleImport to from is+moduleImport to from [] = do+  return $ LispEnv to+ evalfuncLoad [cont@(Continuation _ a b c d), String filename, LispEnv env] = do     evalfuncLoad [Continuation env a b c d, String filename] @@ -917,6 +1034,7 @@                   , ("null-environment", evalfuncNullEnv)                   , ("current-environment", evalfuncInteractionEnv)                   , ("interaction-environment", evalfuncInteractionEnv)+                  , ("%import", evalfuncImport)                   , ("make-environment", evalfuncMakeEnv)                 -- Non-standard extensions@@ -964,10 +1082,16 @@                 ("delete-file", deleteFile),                  -- Other I/O functions+                ("print-env", printEnv'),                 ("read-contents", readContents),                 ("read-all", readAll),                 ("gensym", gensym)] +printEnv' :: [LispVal] -> IOThrowsError LispVal+printEnv' [LispEnv env] = do+    result <- liftIO $ printEnv env+    return $ String result+ {- "Pure" primitive functions -} primitives :: [(String, [LispVal] -> ThrowsError LispVal)] primitives = [("+", numAdd),@@ -1079,6 +1203,16 @@               ("vector-ref", vectorRef),               ("vector->list", vectorToList),               ("list->vector", listToVector),++              ("bytevector?", unaryOp isByteVector),+              ("make-bytevector", makeByteVector),+              ("bytevector", byteVector),+              ("bytevector-length", byteVectorLength),+              ("bytevector-u8-ref", byteVectorRef),+              ("bytevector-append", byteVectorAppend),+              ("bytevector-copy", byteVectorCopy),+              ("utf8->string", byteVectorUtf2Str),+              ("string->utf8", byteVectorStr2Utf),                ("make-hash-table", hashTblMake),               ("hash-table?", isHashTbl),
hs-src/Language/Scheme/Numerical.hs view
@@ -11,10 +11,8 @@ -}  module Language.Scheme.Numerical (-   numericBinop--- , foldlM--- , foldl1M- , numSub+ -- * Generic functions+   numSub  , numMul  , numDiv  , numAdd@@ -26,20 +24,30 @@  , numBoolBinopLt  , numBoolBinopLte  , numCast+ , numDenominator+ , numNumerator+ , numInexact2Exact+ , numExact2Inexact + , num2String+ , unpackNum+ , numericBinop+ -- * Floating point functions  , numFloor  , numCeiling  , numTruncate  , numRound+ , numExpt+ , numSqrt+ , numExp+ , numLog+ -- * Trigonometric functions  , numSin  , numCos  , numTan  , numAsin   , numAcos  , numAtan- , numExpt- , numSqrt- , numExp- , numLog+ -- * Complex functions  , buildComplex  , numMakePolar  , numRealPart@@ -47,18 +55,13 @@  , numMagnitude  , numAngle  , numMakeRectangular- , numDenominator- , numNumerator- , numInexact2Exact- , numExact2Inexact - , num2String+ -- * Predicates  , isComplex  , isReal   , isRational  , isInteger  , isNumber  , isFloatAnInteger- , unpackNum ) where import Language.Scheme.Types @@ -70,6 +73,7 @@ import Numeric import Text.Printf +-- |A helper function to perform a numeric operation on two values numericBinop :: (Integer -> Integer -> Integer) -> [LispVal] -> ThrowsError LispVal numericBinop _ singleVal@[_] = throwError $ NumArgs 2 singleVal numericBinop op aparams = mapM unpackNum aparams >>= return . Number . foldl1 op@@ -89,8 +93,8 @@ numerical types they accept. Within reason, a user should not have to know what numerical type they are passing when using these functions -} --numAdd, numSub, numMul, numDiv, numMod :: [LispVal] -> ThrowsError LispVal+-- |Add the given numbers+numAdd :: [LispVal] -> ThrowsError LispVal numAdd [] = return $ Number 0 numAdd aparams = do   foldl1M (\ a b -> doAdd =<< (numCast [a, b])) aparams@@ -99,6 +103,9 @@         doAdd (List [(Rational a), (Rational b)]) = return $ Rational $ a + b         doAdd (List [(Complex a), (Complex b)]) = return $ Complex $ a + b         doAdd _ = throwError $ Default "Unexpected error in +"++-- |Subtract the given numbers+numSub :: [LispVal] -> ThrowsError LispVal numSub [] = throwError $ NumArgs 1 [] numSub [Number n] = return $ Number $ -1 * n numSub [Float n] = return $ Float $ -1 * n@@ -111,6 +118,9 @@         doSub (List [(Rational a), (Rational b)]) = return $ Rational $ a - b         doSub (List [(Complex a), (Complex b)]) = return $ Complex $ a - b         doSub _ = throwError $ Default "Unexpected error in -"++-- |Multiply the given numbers+numMul :: [LispVal] -> ThrowsError LispVal numMul [] = return $ Number 1 numMul aparams = do   foldl1M (\ a b -> doMul =<< (numCast [a, b])) aparams@@ -119,6 +129,9 @@         doMul (List [(Rational a), (Rational b)]) = return $ Rational $ a * b         doMul (List [(Complex a), (Complex b)]) = return $ Complex $ a * b         doMul _ = throwError $ Default "Unexpected error in *"++-- |Divide the given numbers+numDiv :: [LispVal] -> ThrowsError LispVal numDiv [] = throwError $ NumArgs 1 [] numDiv [Number 0] = throwError $ DivideByZero  numDiv [Rational 0] = throwError $ DivideByZero  @@ -145,6 +158,8 @@                                                        else return $ Complex $ a / b         doDiv _ = throwError $ Default "Unexpected error in /" +-- |Take the modulus of the given numbers+numMod :: [LispVal] -> ThrowsError LispVal numMod [] = return $ Number 1 numMod aparams = do   foldl1M (\ a b -> doMod =<< (numCast [a, b])) aparams@@ -154,6 +169,7 @@         doMod (List [(Complex _), (Complex _)]) = throwError $ Default "modulo not implemented for complex numbers"          doMod _ = throwError $ Default "Unexpected error in modulo" +-- |Numeric equals numBoolBinopEq :: [LispVal] -> ThrowsError LispVal numBoolBinopEq [] = throwError $ NumArgs 0 [] numBoolBinopEq aparams = do@@ -164,6 +180,7 @@         doOp (List [(Complex a), (Complex b)]) = return $ Bool $ a == b         doOp _ = throwError $ Default "Unexpected error in =" +-- |Numeric greater than numBoolBinopGt :: [LispVal] -> ThrowsError LispVal numBoolBinopGt [] = throwError $ NumArgs 0 [] numBoolBinopGt aparams = do@@ -173,6 +190,7 @@         doOp (List [(Rational a), (Rational b)]) = return $ Bool $ a > b         doOp _ = throwError $ Default "Unexpected error in >" +-- |Numeric greater than equal numBoolBinopGte :: [LispVal] -> ThrowsError LispVal numBoolBinopGte [] = throwError $ NumArgs 0 [] numBoolBinopGte aparams = do@@ -182,6 +200,7 @@         doOp (List [(Rational a), (Rational b)]) = return $ Bool $ a >= b         doOp _ = throwError $ Default "Unexpected error in >=" +-- |Numeric less than  numBoolBinopLt :: [LispVal] -> ThrowsError LispVal numBoolBinopLt [] = throwError $ NumArgs 0 [] numBoolBinopLt aparams = do@@ -191,6 +210,7 @@         doOp (List [(Rational a), (Rational b)]) = return $ Bool $ a < b         doOp _ = throwError $ Default "Unexpected error in <" +-- |Numeric less than equal numBoolBinopLte :: [LispVal] -> ThrowsError LispVal numBoolBinopLte [] = throwError $ NumArgs 0 [] numBoolBinopLte aparams = do@@ -200,6 +220,7 @@         doOp (List [(Rational a), (Rational b)]) = return $ Bool $ a <= b         doOp _ = throwError $ Default "Unexpected error in <=" +-- |Accept two numbers and cast one of them to the appropriate type, if necessary numCast :: [LispVal] -> ThrowsError LispVal numCast [a@(Number _), b@(Number _)] = return $ List [a, b] numCast [a@(Float _), b@(Float _)] = return $ List [a, b]@@ -226,6 +247,7 @@   where doThrowError num = throwError $ TypeMismatch "number" num numCast _ = throwError $ Default "Unexpected error in numCast" +-- |Convert the given number to a rational numRationalize :: [LispVal] -> ThrowsError LispVal numRationalize [(Number n)] = return $ Rational $ toRational n numRationalize [(Float n)] = return $ Rational $ toRational n@@ -233,7 +255,8 @@ numRationalize [x] = throwError $ TypeMismatch "number" x numRationalize badArgList = throwError $ NumArgs 1 badArgList -numRound, numFloor, numCeiling, numTruncate :: [LispVal] -> ThrowsError LispVal+-- |Round the given number+numRound :: [LispVal] -> ThrowsError LispVal numRound [n@(Number _)] = return n numRound [(Rational n)] = return $ Number $ round n numRound [(Float n)] = return $ Float $ fromInteger $ round n@@ -242,6 +265,8 @@ numRound [x] = throwError $ TypeMismatch "number" x numRound badArgList = throwError $ NumArgs 1 badArgList +-- |Floor the given number+numFloor :: [LispVal] -> ThrowsError LispVal numFloor [n@(Number _)] = return n numFloor [(Rational n)] = return $ Number $ floor n numFloor [(Float n)] = return $ Float $ fromInteger $ floor n@@ -250,6 +275,8 @@ numFloor [x] = throwError $ TypeMismatch "number" x numFloor badArgList = throwError $ NumArgs 1 badArgList +-- |Take the ceiling of the given number+numCeiling :: [LispVal] -> ThrowsError LispVal numCeiling [n@(Number _)] = return n numCeiling [(Rational n)] = return $ Number $ ceiling n numCeiling [(Float n)] = return $ Float $ fromInteger $ ceiling n@@ -258,6 +285,8 @@ numCeiling [x] = throwError $ TypeMismatch "number" x numCeiling badArgList = throwError $ NumArgs 1 badArgList +-- |Truncate the given number+numTruncate :: [LispVal] -> ThrowsError LispVal numTruncate [n@(Number _)] = return n numTruncate [(Rational n)] = return $ Number $ truncate n numTruncate [(Float n)] = return $ Float $ fromInteger $ truncate n@@ -266,7 +295,7 @@ numTruncate [x] = throwError $ TypeMismatch "number" x numTruncate badArgList = throwError $ NumArgs 1 badArgList -+-- |Sine numSin :: [LispVal] -> ThrowsError LispVal numSin [(Number n)] = return $ Float $ sin $ fromInteger n numSin [(Float n)] = return $ Float $ sin n@@ -275,6 +304,7 @@ numSin [x] = throwError $ TypeMismatch "number" x numSin badArgList = throwError $ NumArgs 1 badArgList +-- |Cosine numCos :: [LispVal] -> ThrowsError LispVal numCos [(Number n)] = return $ Float $ cos $ fromInteger n numCos [(Float n)] = return $ Float $ cos n@@ -283,6 +313,7 @@ numCos [x] = throwError $ TypeMismatch "number" x numCos badArgList = throwError $ NumArgs 1 badArgList +-- |Tangent numTan :: [LispVal] -> ThrowsError LispVal numTan [(Number n)] = return $ Float $ tan $ fromInteger n numTan [(Float n)] = return $ Float $ tan n@@ -291,6 +322,7 @@ numTan [x] = throwError $ TypeMismatch "number" x numTan badArgList = throwError $ NumArgs 1 badArgList +-- |Arcsine numAsin :: [LispVal] -> ThrowsError LispVal numAsin [(Number n)] = return $ Float $ asin $ fromInteger n numAsin [(Float n)] = return $ Float $ asin n@@ -299,6 +331,7 @@ numAsin [x] = throwError $ TypeMismatch "number" x numAsin badArgList = throwError $ NumArgs 1 badArgList +-- |Arccosine numAcos :: [LispVal] -> ThrowsError LispVal numAcos [(Number n)] = return $ Float $ acos $ fromInteger n numAcos [(Float n)] = return $ Float $ acos n@@ -307,6 +340,7 @@ numAcos [x] = throwError $ TypeMismatch "number" x numAcos badArgList = throwError $ NumArgs 1 badArgList +-- |Arctangent numAtan :: [LispVal] -> ThrowsError LispVal numAtan [(Number n)] = return $ Float $ atan $ fromInteger n numAtan [Number y, Number x] = return $ Float $ phase $ (fromInteger x) :+ (fromInteger y)@@ -318,7 +352,8 @@ numAtan [x] = throwError $ TypeMismatch "number" x numAtan badArgList = throwError $ NumArgs 1 badArgList -numSqrt, numExpt :: [LispVal] -> ThrowsError LispVal+-- |Take the square root of the given number+numSqrt :: [LispVal] -> ThrowsError LispVal numSqrt [(Number n)] = if n >= 0 then return $ Float $ sqrt $ fromInteger n                                  else return $ Complex $ sqrt ((fromInteger n) :+ 0) numSqrt [(Float n)] = if n >= 0 then return $ Float $ sqrt n@@ -328,6 +363,8 @@ numSqrt [x] = throwError $ TypeMismatch "number" x numSqrt badArgList = throwError $ NumArgs 1 badArgList +-- |Raise the first number to the power of the second+numExpt :: [LispVal] -> ThrowsError LispVal numExpt [(Number n), (Number p)] = return $ Float $ (fromInteger n) ^ p numExpt [(Rational n), (Number p)] = return $ Float $ (fromRational n) ^ p numExpt [(Float n), (Number p)] = return $ Float $ n ^ p@@ -342,6 +379,7 @@         doExpt (List [(Float a), (Float b)]) = return $ Float $ a ^ b --        doExpt (List [(Complex a), (Complex b)]) = return $ Complex $ a ^ b -} +-- |Take the exponent of the given number numExp :: [LispVal] -> ThrowsError LispVal numExp [(Number n)] = return $ Float $ exp $ fromInteger n numExp [(Float n)] = return $ Float $ exp n@@ -350,6 +388,7 @@ numExp [x] = throwError $ TypeMismatch "number" x numExp badArgList = throwError $ NumArgs 1 badArgList +-- |Compute the log of a given number numLog :: [LispVal] -> ThrowsError LispVal numLog [(Number n)] = return $ Float $ log $ fromInteger n numLog [(Float n)] = return $ Float $ log n@@ -358,8 +397,15 @@ numLog [x] = throwError $ TypeMismatch "number" x numLog badArgList = throwError $ NumArgs 1 badArgList +-- Complex number functions -buildComplex :: LispVal -> LispVal -> ThrowsError LispVal+-- |Create a complex number+buildComplex :: LispVal +             -- ^ Real part+             -> LispVal +             -- ^ Imaginary part+             -> ThrowsError LispVal+             -- ^ Complex number buildComplex (Number x) (Number y) = return $ Complex $ (fromInteger x) :+ (fromInteger y) buildComplex (Number x) (Rational y) = return $ Complex $ (fromInteger x) :+ (fromRational y) buildComplex (Number x) (Float y) = return $ Complex $ (fromInteger x) :+ y@@ -371,48 +417,60 @@ buildComplex (Float x) (Float y) = return $ Complex $ x :+ y buildComplex x y = throwError $ TypeMismatch "number" $ List [x, y] --- Complex number functions-numMakeRectangular, numMakePolar, numRealPart, numImagPart, numMagnitude, numAngle :: [LispVal] -> ThrowsError LispVal+-- |Create a complex number given its real and imaginary parts+numMakeRectangular :: [LispVal] -> ThrowsError LispVal numMakeRectangular [x, y] = buildComplex x y numMakeRectangular badArgList = throwError $ NumArgs 2 badArgList +-- |Create a complex number from its magnitude and phase (angle)+numMakePolar :: [LispVal] -> ThrowsError LispVal numMakePolar [(Float x), (Float y)] = return $ Complex $ mkPolar x y numMakePolar [(Float _), y] = throwError $ TypeMismatch "real" y numMakePolar [x, (Float _)] = throwError $ TypeMismatch "real real" $ x numMakePolar badArgList = throwError $ NumArgs 2 badArgList +-- |The phase of a complex number+numAngle :: [LispVal] -> ThrowsError LispVal numAngle [(Complex c)] = return $ Float $ phase c numAngle [x] = throwError $ TypeMismatch "complex number" x numAngle badArgList = throwError $ NumArgs 1 badArgList +-- |The nonnegative magnitude of a complex number+numMagnitude :: [LispVal] -> ThrowsError LispVal numMagnitude [(Complex c)] = return $ Float $ magnitude c numMagnitude [x] = throwError $ TypeMismatch "complex number" x numMagnitude badArgList = throwError $ NumArgs 1 badArgList +-- |Retrieve real part of a complex number+numRealPart :: [LispVal] -> ThrowsError LispVal numRealPart [(Complex c)] = return $ Float $ realPart c numRealPart [x] = throwError $ TypeMismatch "complex number" x numRealPart badArgList = throwError $ NumArgs 1 badArgList +-- |Retrieve imaginary part of a complex number+numImagPart :: [LispVal] -> ThrowsError LispVal numImagPart [(Complex c)] = return $ Float $ imagPart c numImagPart [x] = throwError $ TypeMismatch "complex number" x numImagPart badArgList = throwError $ NumArgs 1 badArgList --numNumerator, numDenominator :: [LispVal] -> ThrowsError LispVal+-- |Take the numerator of the given number+numNumerator :: [LispVal] -> ThrowsError LispVal numNumerator [n@(Number _)] = return n numNumerator [(Rational r)] = return $ Number $ numerator r numNumerator [(Float f)] = return $ Float $ fromInteger . numerator . toRational $ f---numNumerator [(Float f)] = return $ Float $ fromInteger $ numerator $ toRational f numNumerator [x] = throwError $ TypeMismatch "rational number" x numNumerator badArgList = throwError $ NumArgs 1 badArgList +-- |Take the denominator of the given number+numDenominator :: [LispVal] -> ThrowsError LispVal numDenominator [Number _] = return $ Number 1 numDenominator [(Rational r)] = return $ Number $ denominator r numDenominator [(Float f)] = return $ Float $ fromInteger $ denominator $ toRational f numDenominator [x] = throwError $ TypeMismatch "rational number" x numDenominator badArgList = throwError $ NumArgs 1 badArgList -numExact2Inexact, numInexact2Exact :: [LispVal] -> ThrowsError LispVal+-- |Convert an exact number to inexact+numExact2Inexact :: [LispVal] -> ThrowsError LispVal numExact2Inexact [(Number n)] = return $ Float $ fromInteger n numExact2Inexact [(Rational n)] = return $ Float $ fromRational n numExact2Inexact [n@(Float _)] = return n@@ -420,6 +478,8 @@ numExact2Inexact [badType] = throwError $ TypeMismatch "number" badType numExact2Inexact badArgList = throwError $ NumArgs 1 badArgList +-- |Convert an inexact number to exact+numInexact2Exact :: [LispVal] -> ThrowsError LispVal numInexact2Exact [n@(Number _)] = return n numInexact2Exact [n@(Rational _)] = return n numInexact2Exact [(Float n)] = return $ Number $ round n@@ -444,31 +504,45 @@ num2String [x] = throwError $ TypeMismatch "number" x num2String badArgList = throwError $ NumArgs 1 badArgList -isNumber, isComplex, isReal, isRational, isInteger :: [LispVal] -> ThrowsError LispVal+-- |Predicate to determine if given value is a number+isNumber :: [LispVal] -> ThrowsError LispVal isNumber ([Number _]) = return $ Bool True isNumber ([Float _]) = return $ Bool True isNumber ([Complex _]) = return $ Bool True isNumber ([Rational _]) = return $ Bool True isNumber _ = return $ Bool False +-- |Predicate to determine if given number is complex.+--  Keep in mind this does not just look at the types +isComplex :: [LispVal] -> ThrowsError LispVal isComplex ([Complex _]) = return $ Bool True isComplex ([Number _]) = return $ Bool True isComplex ([Rational _]) = return $ Bool True isComplex ([Float _]) = return $ Bool True isComplex _ = return $ Bool False +-- |Predicate to determine if given number is a real.+--  Keep in mind this does not just look at the types +isReal :: [LispVal] -> ThrowsError LispVal isReal ([Number _]) = return $ Bool True isReal ([Rational _]) = return $ Bool True isReal ([Float _]) = return $ Bool True isReal ([Complex c]) = return $ Bool $ (imagPart c) == 0 isReal _ = return $ Bool False +-- |Predicate to determine if given number is a rational.+--  Keep in mind this does not just look at the types +isRational :: [LispVal] -> ThrowsError LispVal isRational ([Number _]) = return $ Bool True isRational ([Rational _]) = return $ Bool True isRational ([n@(Float _)]) = return $ Bool $ isFloatAnInteger n                              -- FUTURE: not quite good enough, could be represented exactly and not an integer isRational _ = return $ Bool False +-- |Predicate to determine if given number is an integer.+--  Keep in mind this does not just look at the types; +--  a floating point input value can return true, for example.+isInteger :: [LispVal] -> ThrowsError LispVal isInteger ([Number _]) = return $ Bool True isInteger ([Complex n]) = do   return $ Bool $ (isFloatAnInteger $ Float $ realPart n) && (isFloatAnInteger $ Float $ imagPart n)
hs-src/Language/Scheme/Parser.hs view
@@ -20,7 +20,6 @@     , readExpr     , readExprList      -- *Low level parsing-    , symbol     , parseExpr      , parseAtom     , parseBool@@ -36,6 +35,7 @@     , parseEscapedChar      , parseString      , parseVector+    , parseByteVector     , parseHashTable     , parseList     , parseDottedList@@ -47,10 +47,12 @@ import Language.Scheme.Types import Control.Monad.Error import Data.Array+import qualified Data.ByteString as BS import qualified Data.Char as Char import Data.Complex-import Data.Ratio import qualified Data.Map+import Data.Ratio+import Data.Word import Numeric import Text.ParserCombinators.Parsec hiding (spaces) import Text.Parsec.Language@@ -100,9 +102,11 @@ --lexeme :: ParsecT String () Identity a -> ParsecT String () Identity a lexeme = P.lexeme lexer +-- |Match a special character symbol :: Parser Char symbol = oneOf "!$%&|*+-/:<=>?@^_~." +-- |Parse an atom (scheme symbol) parseAtom :: Parser LispVal parseAtom = do   atom <- identifier@@ -110,6 +114,7 @@      then pzero -- Do not match this form      else return $ Atom atom +-- |Parse a boolean parseBool :: Parser LispVal parseBool = do _ <- string "#"                x <- oneOf "tf"@@ -118,6 +123,7 @@                           'f' -> Bool False                           _ -> Bool False +-- |Parse a character parseChar :: Parser LispVal parseChar = do   _ <- try (string "#\\")@@ -129,6 +135,8 @@     "newline" -> Char '\n'     _ -> Char c ++-- |Parse an integer in octal notation, base 8 parseOctalNumber :: Parser LispVal parseOctalNumber = do   _ <- try (string "#o")@@ -139,6 +147,7 @@      1 -> return $ Number $ fromInteger $ (*) (-1) $ fst $ Numeric.readOct num !! 0      _ -> pzero +-- |Parse an integer in binary notation, base 2 parseBinaryNumber :: Parser LispVal parseBinaryNumber = do   _ <- try (string "#b")@@ -149,6 +158,7 @@      1 -> return $ Number $ fromInteger $ (*) (-1) $ fst $ Numeric.readInt 2 (`elem` "01") Char.digitToInt num !! 0      _ -> pzero +-- |Parse an integer in hexadecimal notation, base 16 parseHexNumber :: Parser LispVal parseHexNumber = do   _ <- try (string "#x")@@ -224,6 +234,7 @@   buildResult (Float num) nexp = return $ Float $ num * (10 ** (fromIntegral nexp))   buildResult _ _ = pzero +-- |Parse a rational number parseRationalNumber :: Parser LispVal parseRationalNumber = do   pnumerator <- parseDecimalNumber@@ -241,6 +252,7 @@                 else return $ Rational $ n % pdenominator     _ -> pzero +-- |Parse a complex number parseComplexNumber :: Parser LispVal parseComplexNumber = do   lispreal <- (try (parseRealNumber) <|> try (parseRationalNumber) <|> parseDecimalNumber)@@ -259,6 +271,7 @@   _ <- char 'i'   return $ Complex $ real :+ imag +-- |Parse an escaped character parseEscapedChar :: forall st .                     GenParser Char st Char parseEscapedChar = do@@ -270,6 +283,7 @@     'r' -> '\r'     _ -> c +-- |Parse a string parseString :: Parser LispVal parseString = do   _ <- char '"'@@ -277,11 +291,21 @@   _ <- char '"'   return $ String x +-- |Parse a vector parseVector :: Parser LispVal parseVector = do   vals <- sepBy parseExpr whiteSpace   return $ Vector (listArray (0, (length vals - 1)) vals) +-- |Parse a bytevector+parseByteVector :: Parser LispVal+parseByteVector = do+  ns <- sepBy parseNumber whiteSpace+  return $ ByteVector $ BS.pack $ map conv ns+ where +   conv (Number n) = fromInteger n :: Word8+   conv n = 0 :: Word8+ -- |Parse a hash table. The table is either empty or is made up of --  an alist (associative list) parseHashTable :: Parser LispVal@@ -302,10 +326,12 @@     Just m -> return $ HashTable $ Data.Map.fromList m     Nothing -> pzero +-- |Parse a list parseList :: Parser LispVal parseList = liftM List $ sepBy parseExpr whiteSpace -- TODO: wanted to use endBy (or a variant) above, but it causes an error such that dotted lists are not parsed +-- |Parse a dotted list (scheme pair) parseDottedList :: Parser LispVal parseDottedList = do   phead <- endBy parseExpr whiteSpace@@ -333,24 +359,29 @@        all of R5RS without performing this transformation. -}     _ -> return $ DottedList phead ptail +-- |Parse a quoted expression parseQuoted :: Parser LispVal parseQuoted = do   _ <- lexeme $ char '\''   x <- parseExpr   return $ List [Atom "quote", x] +-- |Parse a quasi-quoted expression parseQuasiQuoted :: Parser LispVal parseQuasiQuoted = do   _ <- lexeme $ char '`'   x <- parseExpr   return $ List [Atom "quasiquote", x] +-- |Parse an unquoted expression (a quasiquotated expression preceded+--  by a comma) parseUnquoted :: Parser LispVal parseUnquoted = do   _ <- try (lexeme $ char ',')   x <- parseExpr   return $ List [Atom "unquote", x] +-- |Parse an unquote-spliced expression parseUnquoteSpliced :: Parser LispVal parseUnquoteSpliced = do   _ <- try (lexeme $ string ",@")@@ -374,6 +405,10 @@          x <- parseVector          _ <- lexeme $ char ')'          return x+  <|> do _ <- try (lexeme $ string "#u8(")+         x <- parseByteVector+         _ <- lexeme $ char ')'+         return x --  <|> do _ <- try (lexeme $ string "#hash(") --         x <- parseHashTable --         _ <- lexeme $ char ')'@@ -390,6 +425,7 @@   <|> brackets parseDottedList   <?> "Expression" +-- |Initial parser used by the high-level parse functions mainParser :: Parser LispVal mainParser = do     _ <- whiteSpace
hs-src/Language/Scheme/Plugins/CPUTime.hs view
@@ -22,14 +22,14 @@ import System.CPUTime import Control.Monad.Error -get, precision :: [LispVal] -> IOThrowsError LispVal- -- |Wrapper for CPUTime.getCPUTime+get :: [LispVal] -> IOThrowsError LispVal get [] = do   t <- liftIO $ System.CPUTime.getCPUTime   return $ Number t get badArgList = throwError $ NumArgs 0 badArgList  -- |Wrapper for CPUTime.cpuTimePrecision+precision :: [LispVal] -> IOThrowsError LispVal precision [] = return $ Number $ System.CPUTime.cpuTimePrecision precision badArgList = throwError $ NumArgs 0 badArgList
hs-src/Language/Scheme/Primitives.hs view
@@ -29,6 +29,15 @@  , vectorToList   , listToVector  , makeVector+ -- ** Bytevectors+ , makeByteVector+ , byteVector+ , byteVectorLength+ , byteVectorRef+ , byteVectorCopy+ , byteVectorAppend+ , byteVectorUtf2Str+ , byteVectorStr2Utf  -- ** Hash Table  , hashTblExists   , hashTblRef@@ -73,9 +82,11 @@  , isProcedure   , isList   , isVector + , isByteVector  , isNull   , isEOFObject   , isSymbol +  -- ** Utility functions  , unpackEquals   , boolBinop @@ -114,10 +125,13 @@ import Language.Scheme.Types --import qualified Control.Exception import Control.Monad.Error+import qualified Data.ByteString as BS+import qualified Data.ByteString.UTF8 as BSU import Data.Char hiding (isSymbol) import Data.Array import Data.Unique import qualified Data.Map+import Data.Word import System.IO import System.Directory (doesFileExist, removeFile) import System.IO.Error@@ -319,7 +333,11 @@ vectorLength [badType] = throwError $ TypeMismatch "vector" badType vectorLength badArgList = throwError $ NumArgs 1 badArgList -vectorRef [(Vector v), (Number n)] = return $ v ! (fromInteger n)+vectorRef [(Vector v), (Number n)] = do+    let len = toInteger $ (length $ elems v) - 1+    if n > len || n < 0+       then throwError $ Default "Invalid index"+       else return $ v ! (fromInteger n) vectorRef [badType] = throwError $ TypeMismatch "vector integer" badType vectorRef badArgList = throwError $ NumArgs 2 badArgList @@ -331,6 +349,71 @@ listToVector [badType] = throwError $ TypeMismatch "list" badType listToVector badArgList = throwError $ NumArgs 1 badArgList +-- ------------ Bytevector Primitives --------------+makeByteVector, byteVector, byteVectorLength, byteVectorRef, byteVectorCopy, byteVectorAppend, byteVectorUtf2Str, byteVectorStr2Utf :: [LispVal] -> ThrowsError LispVal+makeByteVector [(Number n)] = do+  let ls = replicate (fromInteger n) (0 :: Word8)+  return $ ByteVector $ BS.pack ls+makeByteVector [Number n, Number byte] = do+  let ls = replicate (fromInteger n) (fromInteger byte :: Word8)+  return $ ByteVector $ BS.pack ls+makeByteVector [badType] = throwError $ TypeMismatch "integer" badType+makeByteVector badArgList = throwError $ NumArgs 2 badArgList++byteVector bs = do+ return $ ByteVector $ BS.pack $ map conv bs+ where +   conv (Number n) = fromInteger n :: Word8+   conv n = 0 :: Word8++byteVectorCopy [ByteVector bv] = do+    return $ ByteVector $ BS.copy+        bv+byteVectorCopy [ByteVector bv, Number start] = do+    return $ ByteVector $ BS.drop +        (fromInteger start)+        bv+byteVectorCopy [ByteVector bv, Number start, Number end] = do+    return $ ByteVector $ BS.take +        (fromInteger $ end - start)+        (BS.drop +            (fromInteger start)+            bv)+byteVectorCopy [badType] = throwError $ TypeMismatch "bytevector" badType+byteVectorCopy badArgList = throwError $ NumArgs 1 badArgList++byteVectorAppend bs = do+    let acc = BS.pack []+        conv (ByteVector bs) = bs+        conv x = BS.empty+        bs' = map conv bs+    return $ ByteVector $ BS.concat bs'+-- TODO: error handling++byteVectorLength [(ByteVector bv)] = return $ Number $ toInteger $ BS.length bv+byteVectorLength [badType] = throwError $ TypeMismatch "bytevector" badType+byteVectorLength badArgList = throwError $ NumArgs 1 badArgList++byteVectorRef [(ByteVector bv), (Number n)] = do+    let len = toInteger $ (BS.length bv) - 1+    if n > len || n < 0+       then throwError $ Default "Invalid index"+       else return $ Number $ toInteger $ BS.index bv (fromInteger n)+byteVectorRef [badType] = throwError $ TypeMismatch "bytevector integer" badType+byteVectorRef badArgList = throwError $ NumArgs 2 badArgList++byteVectorUtf2Str [(ByteVector bv)] = do+    return $ String $ BSU.toString bv +-- TODO: need to support other overloads of this function+byteVectorUtf2Str [badType] = throwError $ TypeMismatch "bytevector" badType+byteVectorUtf2Str badArgList = throwError $ NumArgs 1 badArgList+byteVectorStr2Utf [(String s)] = do+    return $ ByteVector $ BSU.fromString s+-- TODO: need to support other overloads of this function+byteVectorStr2Utf [badType] = throwError $ TypeMismatch "string" badType+byteVectorStr2Utf badArgList = throwError $ NumArgs 1 badArgList++ -- ------------ Hash Table Primitives --------------  -- Future: support (equal?), (hash) parameters@@ -515,6 +598,10 @@ isVector _ = return $ Bool False isList (List _) = return $ Bool True isList _ = return $ Bool False++isByteVector :: LispVal -> ThrowsError LispVal+isByteVector (ByteVector _) = return $ Bool True+isByteVector _ = return $ Bool False  isNull :: [LispVal] -> ThrowsError LispVal isNull ([List []]) = return $ Bool True
hs-src/Language/Scheme/Types.hs view
@@ -14,21 +14,26 @@ -}  module Language.Scheme.Types-    ( Env (..)+    ( +    -- * Environments+      Env (..)     , nullEnv +    -- * Error Handling     , LispError (..)     , ThrowsError +    , IOThrowsError      , trapError     , extractValue -    , IOThrowsError      , liftThrows      , runIOThrowsREPL      , runIOThrows +    -- * Types and related functions     , LispVal (           Atom         , List         , DottedList         , Vector+        , ByteVector         , HashTable         , Number         , Float@@ -92,11 +97,13 @@ import Control.Monad.Error import Data.Complex import Data.Array+import qualified Data.ByteString as BS import Data.Dynamic import Data.IORef import qualified Data.Map -- import Data.Maybe import Data.Ratio+import Data.Word import System.IO import Text.ParserCombinators.Parsec hiding (spaces) @@ -121,10 +128,10 @@   | TypeMismatch String LispVal -- ^Type error   | Parser ParseError -- ^Parsing error   | BadSpecialForm String LispVal -- ^Invalid special (built-in) form-  | NotFunction String String-  | UnboundVar String String+--  | NotFunction String String+  | UnboundVar String String -- ^ A referenced variable has not been declared   | DivideByZero -- ^Divide by Zero error-  | NotImplemented String+  | NotImplemented String -- ^ Feature is not implemented   | InternalError String {- ^An internal error within husk; in theory user (Scheme) code                          should never allow one of these errors to be triggered. -}   | Default String -- ^Default error@@ -137,7 +144,7 @@                                   ++ ", found " ++ show found showError (Parser parseErr) = "Parse error at " ++ ": " ++ show parseErr showError (BadSpecialForm message form) = message ++ ": " ++ show form-showError (NotFunction message func) = message ++ ": " ++ show func+-- showError (NotFunction message func) = message ++ ": " ++ show func showError (UnboundVar message varname) = message ++ ": " ++ varname showError (DivideByZero) = "Division by zero" showError (NotImplemented message) = "Not implemented: " ++ message@@ -149,19 +156,24 @@   noMsg = Default "An error has occurred"   strMsg = Default +-- |Container used by operations that could throw an error type ThrowsError = Either LispError +-- |Error handler that returns a string description of any error trapError :: -- forall (m :: * -> *) e.             (MonadError e m, Show e) =>              m String -> m String trapError action = catchError action (return . show) +-- |Utility function to unwrap a value from ThrowsError extractValue :: ThrowsError a -> a extractValue (Right val) = val-extractValue (Left _) = error "Unexpected error in extractValue; "+extractValue (Left _) = error "Unexpected error in extractValue" +-- |Container used to provide error handling in the IO monad type IOThrowsError = ErrorT LispError IO +-- |Lift a ThrowsError into the IO monad liftThrows :: ThrowsError a -> IOThrowsError a liftThrows (Left err) = throwError err liftThrows (Right val) = return val@@ -189,6 +201,8 @@  -- ^Pair  | Vector (Array Int LispVal)  -- ^Vector+ | ByteVector BS.ByteString+ -- ^ByteVector from R7RS  | HashTable (Data.Map.Map LispVal LispVal)  {- ^Hash table.  Technically this could be a derived data type instead of being built-in to the@@ -197,9 +211,11 @@  --  -- Map is technically the wrong structure to use for a hash table since it is based on a binary tree and hence operations tend to be O(log n) instead of O(1). However, according to <http://www.opensubscriber.com/message/haskell-cafe@haskell.org/10779624.html> Map has good performance characteristics compared to the alternatives. So it stays for the moment...  --- | Number Integer {- FUTURE: rename this to "Integer" (or "WholeNumber" or something else more meaningful)+ | Number Integer -- ^Integer number+ {- FUTURE: rename this to "Integer" (or "WholeNumber" or something else more meaningful)  Integer -}- | Float Double {- FUTURE: rename this "Real" instead of "Float"...+ | Float Double -- ^Double-precision floating point number+ {- FUTURE: rename this "Real" instead of "Float"...  Floating point -}  | Complex (Complex Double)  -- ^Complex number@@ -247,7 +263,7 @@  | Syntax { synClosure :: Maybe Env       -- ^ Code env in effect at definition time, if applicable           , synRenameClosure :: Maybe Env -- ^ Renames (from macro hygiene) in effect at def time;                                           --   only applicable if this macro defined inside another macro.-          , synDefinedInMacro :: Bool+          , synDefinedInMacro :: Bool     -- ^ Set if macro is defined within another macro           , synIdentifiers :: [LispVal]   -- ^ Literal identifiers from syntax-rules            , synRules :: [LispVal]         -- ^ Rules from syntax-rules    } -- ^ Type to hold a syntax object that is created by a macro definition.@@ -260,7 +276,9 @@  | SyntaxExplicitRenaming LispVal    -- ^ Syntax for an explicit-renaming macro  | LispEnv Env+   -- ^ Wrapper for a scheme environment  | EOF+   -- ^ End of file indicator  | Nil String  -- ^Internal use only; do not use this type directly. @@ -297,19 +315,44 @@  instance Show DynamicWinders where show = showDWVal --- Make an "empty" continuation that does not contain any code+-- |Make an "empty" continuation that does not contain any code makeNullContinuation :: Env -> LispVal makeNullContinuation env = Continuation env Nothing Nothing Nothing Nothing --- Make a continuation that takes a higher-order function (written in Haskell)-makeCPS :: Env -> LispVal -> (Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal) -> LispVal+-- |Make a continuation that takes a higher-order function (written in Haskell)+makeCPS :: Env +        -- ^ Environment+        -> LispVal +        -- ^ Current continuation+        -> (Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal) +        -- ^ Haskell function+        -> LispVal+        -- ^ The Haskell function packaged as a LispVal makeCPS env cont@(Continuation _ _ _ _ dynWind) cps = Continuation env (Just (HaskellBody cps Nothing)) (Just cont) Nothing dynWind makeCPS env cont cps = Continuation env (Just (HaskellBody cps Nothing)) (Just cont) Nothing Nothing -- This overload just here for completeness; it should never be used --- Make a continuation that stores a higher-order function and arguments to that function-makeCPSWArgs :: Env -> LispVal -> (Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal) -> [LispVal] -> LispVal-makeCPSWArgs env cont@(Continuation _ _ _ _ dynWind) cps args = Continuation env (Just (HaskellBody cps (Just args))) (Just cont) Nothing dynWind-makeCPSWArgs env cont cps args = Continuation env (Just (HaskellBody cps (Just args))) (Just cont) Nothing Nothing -- This overload just here for completeness; it should never be used+-- |Make a continuation that stores a higher-order function and arguments to that function+makeCPSWArgs :: Env+        -- ^ Environment+        -> LispVal +        -- ^ Current continuation+        -> (Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal) +        -- ^ Haskell function+        -> [LispVal]+        -- ^ Arguments to the function+        -> LispVal+        -- ^ The Haskell function packaged as a LispVal+makeCPSWArgs env cont@(Continuation _ _ _ _ dynWind) cps args = +    Continuation +        env +        (Just (HaskellBody cps (Just args))) +        (Just cont) Nothing dynWind+makeCPSWArgs env cont cps args = +    -- This overload just here for completeness; it should never be used+    Continuation +        env +        (Just (HaskellBody cps (Just args))) +        (Just cont) Nothing Nothing  instance Ord LispVal where   compare (Bool a) (Bool b) = compare a b@@ -328,7 +371,10 @@   compare a b = compare (show a) (show b) -- Hack (??): sort alphabetically when types differ or have no handlers  -- |Compare two 'LispVal' instances-eqv :: [LispVal] -> ThrowsError LispVal+eqv :: [LispVal] +    -- ^ A list containing two values to compare+    -> ThrowsError LispVal+    -- ^ Result wrapped as a Bool eqv [(Bool arg1), (Bool arg2)] = return $ Bool $ arg1 == arg2 eqv [(Number arg1), (Number arg2)] = return $ Bool $ arg1 == arg2 eqv [(Complex arg1), (Complex arg2)] = return $ Bool $ arg1 == arg2@@ -339,6 +385,7 @@ eqv [(Atom arg1), (Atom arg2)] = return $ Bool $ arg1 == arg2 eqv [(DottedList xs x), (DottedList ys y)] = eqv [List $ xs ++ [x], List $ ys ++ [y]] eqv [(Vector arg1), (Vector arg2)] = eqv [List $ (elems arg1), List $ (elems arg2)]+eqv [(ByteVector a), (ByteVector b)] = return $ Bool $ a == b 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)]@@ -379,6 +426,7 @@                                _ -> False -- OK? eqvList _ _ = throwError $ Default "Unexpected error in eqvList" +-- |A more convenient way to call /eqv/ eqVal :: LispVal -> LispVal -> Bool eqVal a b = do   let result = eqv [a, b]@@ -405,6 +453,7 @@ showVal (Bool True) = "#t" showVal (Bool False) = "#f" showVal (Vector contents) = "#(" ++ (unwordsList $ Data.Array.elems contents) ++ ")"+showVal (ByteVector contents) = "#u8(" ++ unwords (map show (BS.unpack contents)) ++ ")" showVal (HashTable _) = "<hash-table>" showVal (List contents) = "(" ++ unwordsList contents ++ ")" showVal (DottedList h t) = "(" ++ unwordsList h ++ " . " ++ showVal t ++ ")"
hs-src/Language/Scheme/Variables.hs view
@@ -20,6 +20,7 @@       printEnv     , copyEnv     , extendEnv+    , topmostEnv     , findNamespacedEnv     , macroNamespace     , varNamespace @@ -49,11 +50,11 @@ import qualified Data.Map -- import Debug.Trace --- Internal namespace for macros+-- |Internal namespace for macros macroNamespace :: [Char] macroNamespace = "m" --- Internal namespace for variables+-- |Internal namespace for variables varNamespace :: [Char] varNamespace = "v" @@ -100,7 +101,7 @@  where    showVar (name, val) = do     v <- liftIO $ readIORef val-    return $ name ++ ": " ++ show v+    return $ "[" ++ name ++ "]" ++ ": " ++ show v  -- |Create a deep copy of an environment copyEnv :: Env      -- ^ Source environment@@ -118,6 +119,13 @@          ref <- newIORef x          return (name, ref) +-- -- |Perform a deep copy of an environment's contents to a new environment+-- importEnv +--   :: Env -- ^ Source environment+--   -> Env -- ^ Destination environment+--   -> IO () = do+-- -- TODO: need to do this recursively?+ -- |Extend given environment by binding a series of values to a new environment. extendEnv :: Env -- ^ Environment            -> [((String, String), LispVal)] -- ^ Extensions to the environment@@ -130,6 +138,13 @@  where addBinding ((namespace, name), val) = do ref <- newIORef val                                                 return (getVarName namespace name, ref) +-- |Find the top-most environment+topmostEnv :: Env -> IO Env+topmostEnv envRef = do+    case parentEnv envRef of+        Just p -> topmostEnv p+        Nothing -> return envRef+ -- |Recursively search environments to find one that contains the given variable. findNamespacedEnv      :: Env      -- ^Environment to begin the search; @@ -219,8 +234,24 @@ setNamespacedVar envRef                  namespace                  var value = do -  _ <- updatePointers envRef namespace var -  _setNamespacedVar envRef namespace var value+  -- Issue #98 - Need to detect circular references+  --+  -- TODO:+  -- Note this implementation is rather simplistic since+  -- it does not take environments into account. The same+  -- variable name could refer to 2 different variables in+  -- different environments.+  case value of+    Pointer p env -> do+      if p == var +          then return value+          else next+    _ -> next++  where +    next = do+      _ <- updatePointers envRef namespace var +      _setNamespacedVar envRef namespace var value  -- |An internal function that does the actual setting of a  --  variable, without all the extra code that keeps pointers
husk-scheme.cabal view
@@ -1,5 +1,5 @@ Name:                husk-scheme-Version:             3.6.2+Version:             3.6.3 Synopsis:            R5RS Scheme interpreter, compiler, and library. Description:            <<https://github.com/justinethier/husk-scheme/raw/master/docs/husk-scheme.png>>@@ -56,7 +56,7 @@     default: True  Library-  Build-Depends:   base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory+  Build-Depends:   base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory, bytestring, utf8-string   Extensions:      ExistentialQuantification   Hs-Source-Dirs:  hs-src   Exposed-Modules: Language.Scheme.Core
lib/stdlib.scm view
@@ -323,6 +323,18 @@      (set! _vec            (make-vector (vector-length _vec) _fill))))) +; Bytevector Section++; TODO: add appropriate overloads, also note this is not the+; fastest implementation+(define (bytevector-copy! to at from start end)+  (do ((i 0 (+ i 1)))+      ((= i (- end start)))+    (bytevector-u8-set! +        to+        (+ at i) +        (bytevector-u8-ref from (+ start i)))))+ ; Continuation Section (define (values . things)     (call-with-current-continuation